堆的应用(优先级队列、海量数据处理、堆排序)
来源:互联网 发布:淘宝全球购认证 编辑:程序博客网 时间:2024/06/13 21:33
一、优先级队列
1、基本思路
其实可以使用队列来实现,但是不可避免的是Push()和Pop()操作,至少有一个的时间复杂度为O(N),另一个的时间复杂度为O(1),而使用对可以做到插入时时间复杂度为O(lgN),,删除时时间复杂度为O(1)
2、具体实现
是通过适配器模式来实现的,通过对Heap的封装
(1)堆的实现
具体实现前面已有博客讲解过,这里就不具体讲解了
(2)优先级队列的实现
template<class T,template<class> class Compare=Less>class PriorityQueue{public:void Push(const T& x){_hp.Push(x);}void Pop(){_hp.Pop();}T& Top(){return Top();}size_t Size(){return _hp.Size();}bool Empty(){return _hp.Empty();}protected:Heap<T, Compare> _hp;};
二、100w个数中找出最大的前K个数
1、基本思路
(1)方法一:生成一个大小为100的数组,燃油遍历一边这100w个数
(2)方法二:将这100w个数放入到内存中去,然后排序,找去前100个数
(3)方法三:前两者的时间复杂度都太高,效率太低,所以不采用以上两种方法,使用堆来实现
2.具体思路
到底是使用 大根堆来实现还是用小根堆来实现呢?
大根堆和小根堆可以保证第一个数是最小或最小的。如果选择大根堆的话,那么就只能保证这100个选出来的数中第一个数是最大的,因为次大的数有可能进不来,(那么为什么不和最小的叶子节点做比较,因为最小的叶子节点并不能保证它是已经选择出来的100个数中最小的)
所以选择小根堆,比选出来的100个数最小的大的数便会进入堆中,并且会下调,就可以始终保证根节点的值是最小的
三、海量数据处理
1.题目
2015年春节期间,A公司的支付软件某宝和T公司某信红包大乱战。春节后高峰以后,公司Leader要求后台的攻城狮对后台的海量数据进行分析。先要求分析出各地区发红包金额最多的前100用户。现在知道人数最多的s地区大约有1000w用户。要求写一个算法实现。
2、基本思路
其实和应用二的基本思路相同。通过对数组下标1到100之间的元素建成一个堆,然后后面的元素不断和根节点来比较,从而决定是进堆还是不进堆
3.具体实现
代码如下:
void AdjustDown(int* pKArray, size_t root, size_t size){size_t parent = root;size_t child = root * 2 - 1;while (child < size){if (child + 1 < size&&pKArray[child + 1] < pKArray[child]){++child;}if (pKArray[parent] > pKArray[child]){std::swap(pKArray[parent], pKArray[child]);parent = child;child = parent * 2 + 1;}else{break;}}}void GetTopK(const vector<int>& moneys, int n, int k){assert(n > k);int* topKArray = new int[k];for (size_t i = 0; i < k; ++i){topKArray[i] = moneys[i];}//建小根堆for (int i = (k - 2) / 2; i >= 0; --i){AdjustDown(topKArray, 0, k);}for (size_t i = 0; i < k; ++i){cout << topKArray[i] << " ";}cout << endl;delete[] topKArray;}void GreatRedPacket(vector<int>& moneys){srand(time(0));moneys.reserve(N);for (int i = 0; i < N; ++i){moneys.push_back(rand() % 1000);}for (int j = N - K; j < N; ++j){moneys[j] = rand()%N;}}
测试用例:
void Test(){vector<int> arr;GreatRedPacket(arr);GetTopK(arr,N,K);cout << endl;}
三、堆排序
1.基本思路:
堆排序其实是选择排序的一种,只不过每次都要重新建堆
2、集体思路
以升序做为例子来讲:
那么是建大堆还是小堆呢?
(1)建小堆的话,确实下标最小的元素的确是最小的,但是每次选出最小的之后,剩下的都要从新再调整为一个小堆
(2)建大堆的话,根节点是最大的值,每次和最后一个叶子节点的值做交换,接下来将交换后的根节点向下调整,这样就不用从新建堆了
3.具体实现
实现升序
代码如下:
void AdjustDown(int* a, size_t size, size_t root){size_t parent = root;size_t child = parent * 2 + 1;while (child < size){if (child + 1 < size&&a[child + 1] > a[child]){++child;}if (a[child]>a[parent]){std::swap(a[child], a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}void HeapSort(int* a, size_t size){//见堆for (int i = (size-2) / 2; i >= 0; --i){AdjustDown(a, size, i);}for (size_t i = 0; i < size; ++i){std::swap(a[0], a[size - i - 1]);//最后一个数的下标AdjustDown(a, size - i - 1, 0);//个数}}
测试用例:
void Test(){int a[] = { 10, 11, 12, 14, 12, 1, 2, 3, 4, 15, 19 };int len = sizeof(a) / sizeof(a[0]);HeapSort(a, len);for (size_t i = 0; i < len; ++i){cout << a[i] << " ";}}
- 堆的应用(优先级队列、海量数据处理、堆排序)
- 堆(优先级队列) 的应用
- 堆&&堆排序&&优先级队列
- 堆排序的应用之优先级队列的实现
- 算法导论:堆排序的应用---优先级队列
- 数据结构—堆排序及其应用(优先级队列)
- 优先级队列和堆的应用
- 堆的应用——优先级队列
- 堆的应用——优先级队列
- 堆(heap)、堆排序(heapSort)、优先级队列
- 堆、堆排序、优先级队列(c++实现)
- 堆、优先级队列和堆排序
- [数据结构] 二叉堆,堆排序,优先级队列
- 堆(优先级队列)
- 堆排序和优先级队列
- 优先级队列与堆排序
- 堆排序和优先级队列
- 优先级队列与堆排序
- ACM-ICPC是什么样的比赛
- Java 父类子类的对象初始化过程
- js操作map
- 在项目中开发中的一些经验
- Angular构建简单应用的步骤分解
- 堆的应用(优先级队列、海量数据处理、堆排序)
- DLL+ ActiveX控件+WEB页面调用例子
- BCGSoft Demo示例展示之一般示例集合(1/2)
- MyBatis+MySQL数据库操作小技巧
- Linux用户空间与内核空间
- arping IP冲突问题
- Spring MVC的安全隐患及建议
- 开源的新浪微博 Android 客户端:Aisen源码项目
- Entity Framework 中的Code First 中引入数据库函数