文章目录
一、海量数据的前n大/前n小/Top k问题
海量数据求top k的问题要用到容器和堆
二、大根堆/小根堆
1、大根堆(求最小的前n个数)
2、小根堆(求最大的前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;
}