topK問題
在海量數據中找出出現頻率最高的前k個數,或者從海量數據中找出最大的前k個數,這類問題通常被稱爲topK問題。
N個數中取最大的K個數,用小根堆;N個數中取最小的K個數,用大根堆;時間複雜度O(NlogK)。
例題1:100萬個數中,找到其中最大的100個數。(N個數中取最大的K個數)
思路:
(1) 定義兩個數組,arr用於存儲海量數據N,top用於存儲小根堆K;
(2) 將海量數據的前K個元素先填滿top堆;
(3) 調整top堆爲最小堆結構;
(4) 通過遍歷將新數據與堆頂元素(此時堆頂元素最小)比較,大於堆頂元素就入堆,並下調堆結構。
(5) 遍歷結束,則堆中的元素即N個數中最大的前K個數。
代碼如下:
#include<iostream>
#include<cassert>
#include<ctime>
using namespace std;
const int N = 100000;
const int K = 10;
void adjustDown(int *top, int i)
{
int child = 2 * i + 1;
int min = i;
while (min < K/2)
{
if (child + 1 < K&&top[child] > top[child + 1])
child++;
if (child<K&&top[min]>top[child])
{
swap(top[min], top[child]);
min = child;
child = 2 * min + 1;
}
else
break;
}
}
void topK(int *arr, int *top)
{
assert(arr != nullptr&&top != nullptr);
for (int i = 0; i < K; i++)
{
top[i] = arr[i];
}
for (int i = K / 2 - 1; i >= 0; i--)
{
adjustDown(top, i);
}
for (int i = K; i < N; i++)
{
if (arr[i]>top[0])
{
top[0] = arr[i];
adjustDown(top, 0);
}
}
for (int i = 0; i < K; i++)
cout << top[i] << " ";
cout << endl;
}
int main()
{
int arr[N];
int top[K];
srand((unsigned)time(0));//隨機種子
for (size_t idx = 0; idx < N; ++idx)
{
arr[idx] = rand() % 10000;
}
topK(arr, top);
return 0;
}