(二叉)堆的几个应用

来源:互联网 发布:淘宝天狼月季花真的吗 编辑:程序博客网 时间:2024/05/29 16:47

转载地址:http://www.cnblogs.com/chihits/archive/2011/05/02/1987637.html

1. 用作Priority Queue,这个很经典了。不说了。

2. 把多个有序容器里面的元素合并到一个大的有序容器里面。
假设有n个有序容器,我们希望把这些容器里面的元素有序地放到一个大容器里面去。我们姑且称n个有序容器为小容器。对每个小容器维护一个cursor,cursor刚开始指向小容器中的第一个元素,即最小的元素。每个循环中,对n个cursor指向的n个元素建立一个最小堆;从这个堆里面extract最小的元素加到大容器里面;被extract最小元素的那个小容器的cursor往后挪一位;进入下一个循环。如果一个容器的cursor到达end了,那么最小堆的大小减一。
因为我们每次加入到大容器里面的都是当前所有小容器中最小的元素,所以大容器是有序的。 


3. 寻找n个数里面最大的m个数(一个朋友前一段时间在google总部面试的时候被问到这个题目)
首先对前m个数建立一个大小为m的最小堆(注意是最小堆,如果找的是最小的m个数那么建立最大堆),对于下面的每一个数,比较它与最小堆的根(也就是最小堆中的最小的元素,我们称为当前最小值)的大小。如果新的值比当前最小值小,那么就算了,skip it;如果新的值比当前最小值大,把最小值删掉,把新的值插入到最小堆中,然后进行堆调整。算法的复杂度为O(n lg m)。
这样以来,我们可以保证,每个循环过后,最小堆里面维持的始终是最大的m个数(可以看作是循环不变量)。那么处理完n个数之后,最小堆得到的也是最大的m个数。
这个题目最straightforward的方法当然是把n个数排序,复杂度为O(n lg n)。还有一种方法就是基于快速排序思想的random selection。random-select(array, n, k)可以找出长度为n的array数组中最大(小)的第k个数,同时把array划分成两个部分,前一部分比array[k]小(大),后一部分比array[k]大(小)。在期望水平下,这个算法是线性的。


4. 一组不断产生的随机数中找到并维持中位数的值。(英文表述:numbers are randomly generated and passed to a method. Write a program to find and the maintain the median value as new values are generated.)
想法是维持一个最大堆和一个最小堆。最大堆维持小于median的元素,最小堆维持大于median的元素。如果新进来的元素比median小,就插入最大堆;比median大,就插入最小堆。同时两个堆的size始终是相等或者最大堆比最小堆多一个(当然最小堆比最大堆多一个也可以);这个性质很容易维持,我们只要把一个元素从一个堆转到另一个堆就可以了。

0 0