海量数据TopK问题
1.需求
从海量数据中找出出现次数最少的前K个值,且算法复杂度为O(n)。
2.分析
可以使用大根堆来实现。迭代数据,在迭代过程中,堆里面维护了目前为止的遇到的前K个重复次数最小的元素。迭代完成时,取出即可。
Tips:求最小/最少用大根堆,求最多/最大用小根堆。
3.代码实现
#include <iostream>
#include <queue>
#include <ctime>
#include <random>
#include <vector>
#include <unordered_map>
#include <functional>
using namespace std;
// 利用大根堆求数据重复次数最小的的前K个值问题
// 镜像问题同解
int main() {
vector<int> nums;
srand(time(nullptr));
for (int i = 0; i < 10000; ++i) {
nums.push_back(rand() % 1000);
}
unordered_map<int, int> cntHash;
for (int i : nums) {
cntHash[i]++;
}
using Type = pair<int, int>;
using Cmp = function<bool(const Type&, const Type&)>;
// 自定义比较器,创建大根堆
priority_queue<Type, vector<Type>, Cmp> maxHeap(
[](const Type& lhs, const Type& rhs) {
return lhs.second < rhs.second;
}
);
int K = 3;
auto it = cntHash.begin();
for (int i = 0; i < K; ++i, ++it) {
maxHeap.push(*it);
}
while (it != cntHash.end()) {
if (it->second < maxHeap.top().second) {
maxHeap.pop();
maxHeap.push(*it);
}
++it;
}
while (!maxHeap.empty()) {
cout << "key:" << maxHeap.top().first <<
" cnt:" << maxHeap.top().second << endl;
maxHeap.pop();
}
return 0;
}
4.算法复杂度
大根堆的调整为O(logk)的时间复杂度,k为大根堆的层数。因此是常量时间,可以去掉。只剩下O(n)的遍历元素的时间。