zoukankan      html  css  js  c++  java
  • 排序算法之堆排序(优先队列)

    1、堆排序的堆,其实是一个 完全二叉树。既是一个结点要么是叶子结点,要么必定有左右两个子节点的树。

    2、堆有序:每个结点的值,都必须大于两个子节点。但是两个子结点的大小不作要求。

    3、一棵大小为N的完全二叉树,高度为lgN(层)。

    用数组实现堆,假设数组下标从0开始,下标为k的元素,它的左子树是2k+1,右子树是左子树+1,即2k+2

    一:由上至下的有序化(下沉)

    如果堆的有序状态,因为某个结点比它的两个子结点或者其中之一小而打破了,那么可以通过与两个子结点中的较大者来交换。

    交换后可能会在子结点处打破原有序状态,那么只需要继续下沉,直至叶子结点。

    因为是在子树中做交换,对树的其他分支并没有影响。

    //下沉维护堆
    	public static void sink(int[]a,int k,int N){
    		
    		
    		
    		while(2*k+1<=N){
    			
    			
    			int j = 2*k+1;//左孩子的下标
    			
    			//j<N,说明存在右孩子
    			//a[j]<a[j+1],左孩子小于右孩子
    			if(j<N&&a[j]<a[j+1]) 
    				j++;
    			
    			//如果根结点并没有小于他的孩子,不用下沉了
    			if(!(a[k]<a[j]))
    				break;
    			
    			//否则
    			Example.exch(a, k, j);
    			
    			//交换后,更改当前,继续下沉
    			k=j;
    			
    			
    		}//end while
    		
    		
    		
    	}//end sink

    二:下沉实现的堆排序(原地排序)

    1、构建堆

    对于一个普通的数组,我们可以将他看成一个无序的堆。

    要使用堆排序,第一步就要将该数组构造成一个有序堆。

    一个简单的思想是,创建一个新数组,通过堆的插入元素方法,一个一个插入原数组的元素,进而完成一个新堆。

    其实并不需要,我们只要将前N/2的元素,下沉到合适的位置即可,此时堆即有序,后N/2全是叶子结点,无需下沉。

    2、下沉排序

    根据定义,根结点,既是数组的0位元素,永远是有序堆的最大值。

    所以我们只需要将它和数组最后一个元素交换位置,再将大小为N-1的数组(除去最后一个元素,因为他是最大值,放在最后),从新构建成一个新堆即可。怎么构建呢?就是把新的0号元素下沉到适合的位置。

    如此往复,即可得到一个有序的数组。

    //下沉排序
    	public static void sort(int []a){
    		
    		
    		//构建堆
    		//一开始可以将数组看作无序的堆
    		//将从下标为N/2开始一直到0的元素下沉到合适的位置即可。N/2后面的元素,其实都是叶子结点,无需下沉。
    		int N = a.length-1;
    		
    		for(int k = N/2;k>=0;k--){
    			
    			sink(a,k,N);
    			
    		}
    		
    		
    		
    		
    		//下沉排序
    		//堆的根结点永远是最大值,我们只需将最大值和最后一位的元素互换位置。然后再维护一个除原最大结点以外的N-1的堆,再将新堆的根节点放在倒数第二的位置。如此反复
    		
    		while(N>0){
    			
    			Example.exch(a, 0, N--);
    			sink(a,0,N);
    			
    		}
    		
    		
    	}//end sort
    

    时间复杂度:

    主要是下沉,其实下沉的时间复杂度非常直观,每次下沉,结点的高度-1,一棵树的高度是lgN,所以从0号位下沉到最后一位(最坏情况),也只是lgN。

    后面我们在下沉排序里面对每个元素其实都进行了下沉,所以总的来说是NlgN。

    空间复杂度:

    我们在该算法中,并没有用到临时变量或者新建的数组,所以不需要额外的空间。复杂度是常数。

    稳定性:

    不稳定

  • 相关阅读:
    路径变量@PathVariable/请求参数@RequestParam的绑定以及@RequestBody
    JSR303后端校验详细笔记
    创建ssm项目步骤
    利用 R 绘制拟合曲线
    在 Linux 中将 Caps 根据是否为修饰键分别映射到 esc 和 Ctrl
    Master Transcription Factors and Mediator Establish Super-Enhancers at Key Cell Identity Genes
    Genomic Evidence for Complex Domestication History of the Cultivated Tomato in Latin America
    Variation Revealed by SNP Genotyping and Morphology Provides Insight into the Origin of the Tomato
    The genetic, developmental, and molecular bases of fruit size and shape variation in tomato
    微信支付jsapi
  • 原文地址:https://www.cnblogs.com/wzben/p/6151670.html
Copyright © 2011-2022 走看看