版权声明:转用请注明出处 https://blog.csdn.net/weixin_39411321/article/details/89208219
海量数据求top k的问题要用到容器和堆
大根堆(求最小的前n个数)
小根堆(求最大的前n个数)
堆的实质其实就是一颗完全二叉树
最大堆的特点:父节点值均大于子节点;(堆顶元素最大)
最小堆的特点:父节点值均小于子节点;(堆顶元素最小)
找top最大的用小根堆;找top最小的用大根堆
最大堆找top k小代码的基本思路:求前n个最小的数 先建立最大堆 把海量数据向最大堆添加n个数,然后堆的内部会自动排序 我们不用管它的内部是怎么操作的 接下来我们往最大堆进行插入操作 因为最大堆的特点就是堆顶元素最大 若插入元素大于堆顶元素 则它大于堆中任何一个元素 所以摒弃该元素 遍历下一个元素 若插入元素小于堆顶元素则进行插入 插入后堆内自动排序 堆顶元素又成为该堆的最大元素 原堆顶元素出堆 持续遍历完 得到的就是所有元素中最小的前n个数
最小堆找top k大代码的基本思路:求前n个最大的数 先建立最小堆 把海量数据向最小堆添加n个数,堆的内部会自动排序 不用管它的内部是什么操作 然后我们往最小堆进行插入操作 因为最小堆的特点就是堆顶元素最小 若插入元素小于堆顶元素 则它小于堆中任何一个元素 所以摒弃该元素 遍历下一个元素 若插入元素大于堆顶元素则进行插入 插入后堆内自动排序 堆顶元素又成为该堆的最小元素 原堆顶元素出堆 持续遍历完 得到的就是所有元素中最大的前n个数
接下来我们看一看代码吧
如下:
int main()
{
//在最短时间内找到所有整数中最大/最小的n个数并且打印;
//找top最大的用小根堆;找top最小的用大根堆
//时间复杂度 O(n)*log2 n
//===================最大堆找最小值======================
vector<unsigned int>vec;
for (unsigned int i = 0; i < 20000; ++i)
{
vec.push_back(rand() + i); //随机产生两万个数据放在vector容器中
}
priority_queue<int> maxHeap; //声明最大堆
int k = 10;//求20000个数据中前10小个数
for (int i = 0; i < k; i++)
{
maxHeap.push(vec[i]);//先往最大堆中放10个数
}
for (int i = k; i < 20000; ++i)
{
//遍历判断容器中剩余的每个数与堆顶元素的大小
//若小于堆顶元素 则把堆顶元素出堆 把该元素入堆
if (vec[i] < maxHeap.top())
{
maxHeap.pop();
maxHeap.push(vec[i]);
}
}
while (!maxHeap.empty())
//打印最大堆里边的十个最小的数
{
cout << maxHeap.top() << " ";
maxHeap.pop();
}
cout << endl;
//==========================================================
//==========================最小堆找最大值===================
for (unsigned int i = 0; i < 20000; ++i)
{
vec.push_back(rand() + i);
}
priority_queue<int, vector<int>, greater<int>> minHeap; //建立最小堆
//注意:最小堆要加上greater<int>
int j = 10;
for (int i = 0; i < j; i++)
{
minHeap.push(vec[i]);
}
for (int i = j; i < 20000; ++i)
{
//遍历判断容器中剩余的每个数与堆顶元素的大小
//若大于堆顶元素 则把堆顶元素出堆 把该元素入堆
if (vec[i] > minHeap.top())
{
minHeap.pop();
minHeap.push(vec[i]);
}
}
while (!minHeap.empty())
{
//打印最大堆里边的十个最小的数
cout << minHeap.top() << " ";
minHeap.pop();
}
cout << endl;
return 0;
}
运行结果如下:
备注:本来想用更大的数据 但是电脑运行太慢了 半天跑不出来 所以挑了个小一点的数字