題目:給定一個數組,求取前k個最大的數。返回的k個數不要求有序。
topk大問題:
1.先利用快排或者堆排序進行全局排序後取前k個數即可。時間複雜度爲o(nlogn)+o(k)
2.利用快排的思路
(1)先選擇一個劃分基準,然後依次遍歷數組,將大於劃分基準的數放在左邊,小於劃分基準的數放在右邊
(2)記左邊序列和劃分基準的元素個數爲len,如果len等於k,則已經找到;如果len小於k,則需要在右邊的
序列中找len-k個最大數;如果len大於k,則需要在左邊的序列中找k個最大數。依次遞歸找到topk。
時間複雜度爲o(nlogk)
3.利用堆排序的思路,找topk大利用最小堆,找topk小利用最大堆
(1)先去數組的前k個元素建立最小堆
(2)從第k+1個元素開始遍歷,如果當前元素比小堆頂元素大,則交換,然後調整堆。
時間複雜度爲o(nlogk)
如果給定的數據量很大的情況大,不能直接將數據加載到內存當中時,採用堆排序的方法。
尋找topk小的思路也一樣,就是利用最大堆,如果如果當前元素比大堆頂小,則交換。
下面給出第2,3方法的實現topk大。
#include "pch.h"
#include <iostream>
using namespace std;
//交換元素的函數
void swap(int a[], int i, int j)
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
/**********************利用快排思想***************************************/
/*
功能:找到劃分基準的位置
參數:
-a:輸入的數組
-first:起始下標
-last:最後下標
返回:
劃分基準的位置
*/
int partiton(int a[], int first,int last)
{
int storeIndex = first;//當前存儲位置
//選擇last作爲劃分基準
for (int i = first; i < last; i++)
{
if (a[i] > a[last])
{
swap(a, storeIndex, i);
storeIndex++;
}
}
//將last與當前儲存位置交換
swap(a, storeIndex, last);
return storeIndex;
}
/*
功能:找到topk大,a[0]-a[k-1]
參數:
-a:輸入的數組
-first:起始下標
-last:最後下標
-k:要找的前最大元素個數
返回:
無
*/
void quickFindMaxK(int a[], int first, int last, int k)
{
int p = partiton(a, first, last);//尋找劃分基準位置
int len = p - first + 1;//記錄左邊序列與劃分基準的元素個數
if (len == k)
return;
else if (len < k)
quickFindMaxK(a, p + 1, last, k - len);
else
quickFindMaxK(a, first, p-1, k);
}
int main()
{
int a[5] = { 1,2,7,8,5 };
int k = 3;
quickFindMaxK(a, 0, 4, k);
for (int i = 0; i < k; i++)
cout << a[i] << " ";
cout << endl;
}
#include "pch.h"
#include <iostream>
using namespace std;
//交換元素的函數
void swap(int a[], int i, int j)
{
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
/**********************利用最小堆思想***************************************/
/*
功能:調整堆成爲最小堆
參數:
-a:輸入的數組
-len:數組長度
-i:待調整的元素下標
返回:
無
*/
void adjustHeap(int a[], int len,int i)
{
int minIndex = i;
//如果左節點值比父節點小
if (2 * i + 1 < len&&a[2 * i + 1] < a[i])
minIndex = 2 * i + 1;
//如果右節點值比父節點小
if (2 * i + 2 < len&&a[2 * i + 1] < a[i])
minIndex = 2 * i + 1;
if (minIndex != i)
{
swap(a, minIndex, i);
//重新調整堆
adjustHeap(a, len, minIndex);
}
}
/*
功能:建立最小堆
參數:
-a:輸入的數組
-len:數組長度
返回:
無
*/
void buildMinHeap(int a[], int len)
{
//從最後一個非葉子節點從下往上建立最小堆
for (int i = (len - 2) / 2; i >= 0; i--)
adjustHeap(a, len, i);
}
/*
功能:找出topk大,a[0]-a[k-1]
參數:
-a:輸入的數組
-len:數組長度
-k:最大元素個數
返回:
無
*/
void heapFindMaxK(int a[], int len,int k)
{
//用前k個元素建立最小堆
buildMinHeap(a, k);
for (int i = k; i < len; i++)
{
if (a[i] > a[0])
{
swap(a, 0, i);
adjustHeap(a, k, 0);
}
}
}
int main()
{
int a[5] = { 1,2,7,8,5 };
int k = 3;
heapFindMaxK(a,5, k);
for (int i = 0; i < k; i++)
cout << a[i] << " ";
cout << endl;
}