• 堆排序 海量数据求前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元素,效率很高。

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

    建立堆

            /**
    * 将建立堆的过程看作是每次向堆中插入一个数据
    * 每次插入数据都是在插入堆的尾部,然后进行堆调整
    * 说明:每次调整的时候,只需要向上调整即可,由于每次调整之后的子节点的值总是大于父节点
    *     当前插入放入节点向上一层一层调整时,始终保持子堆依然是最小堆结构
    *     如      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/

  • 相关阅读:
    Nginx URL后面不加斜杠301重定向
    Jenkins 配置 Node.js 项目
    在 Linux 上搭建IntelliJ IDEA license server服务器
    Vue 使用细节收集
    sinopia 搭建记录
    cli 开发记录
    Cgroup(一)简介
    Kubernetes (一)POD驱逐
    RabbitMQ(五)镜像队列
    RabbitMQ(四)队列结构
  • 原文地址:https://www.cnblogs.com/wennian/p/5036912.html
Copyright © 2020-2023  润新知