堆排序 海量数据求前N大的值

最(大)小堆的性质

(1)是一颗完全二叉树,遵循完全二叉树的所有性质。

(2)父节点的键值(大于)小于等于子节点的键值

堆的存储

一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。

堆排序  海量数据求前N大的值

海量数据前n大,并且n比较小,堆可以放入内存

【基本原理及要点】

          最大堆求前n小,最小堆求前n大。方法,比如求前n小,我们比较当前元素与最大堆里的最大元素,如果它小于最大元素,则应该替换那个最大元 素。这样最后得到的n个元素就是最小的n个。适合大数据量,求前n小,n的大小比较小的情况,这样可以扫描一遍即可得到所有的前n元素,效率很高。

【扩展】

          双堆,一个最大堆与一个最小堆结合,可以用来维护中位数。

建立堆

        /**

* 将建立堆的过程看作是每次向堆中插入一个数据

* 每次插入数据都是在插入堆的尾部,然后进行堆调整

* 说明:每次调整的时候,只需要向上调整即可,由于每次调整之后的子节点的值总是大于父节点

*     当前插入放入节点向上一层一层调整时,始终保持子堆依然是最小堆结构

*     如      10

*             /     \

*           14     17

*          /   \     /   \

*       18  15 20   37

*      插入节点13时,13为18的子节点,需交换,此时13为父节点,同时由于13小于14,再次交换
         *      注意这里不要调整13的子树的结构,因为13的子树都是向上调整子最小堆得来,因此13的子树本身满足最小堆结构

*/

 java代码实现
void minHeapBuild(int[] num,int index){
//num[0,1..index-1]为已经实现的最小堆,index为插入num[index]值,建立新的堆
int length=num.length;
if(length<=0)
return;
int p=parent(index);
while(p>=0&&index!=0){
if(num[index]>=num[p])
break;
else{
//交换节点
int tmp=num[index];
num[index]=num[p];
num[p]=tmp; //重定位当前节点
index=p;
p=parent(index);
}
}
}

堆的删除

         /** 堆的删除,每次都是删除堆顶的元素,删除后对堆进行调整* 具体做法是用堆尾部的元素代替堆顶元素,然后调整堆*/

java代码实现
void minHeapDelete(int[] num, int len){
int length=num.length;
if(len>=length||len==0)
return;
int p=0;
int child=leftChild(p);
num[p]=num[len-1];//堆尾元素置于堆顶
while(child<len){
//找到左右子节点的较小值
if(child+1<len && num[child]>num[child+1])
child+=1;
if(num[p]<=num[child])
break;
else{
//交换节点
int tmp=num[child];
num[child]=num[p];
num[p]=tmp; //重定位当前父节点
p=child;
child=leftChild(p);
}
} }
int parent(int i){return (i-1)/2;}
int leftChild(int i){return 2*i+1;}

部分参考:http://blog.163.com/xychenbaihu@yeah/blog/static/132229655201351984231220/

                 http://blog.csdn.net/morewindows/article/details/6709644/


上一篇:ubuntu 14 编译视频第三方库ijkplayer,能够在winows下使用


下一篇:新版raspbian系统的固定IP配置和启用root账户的ssh登录功能的方法