堆排序

堆排序的概念相信大家都有所了解,单纯看代码的话,还是有点生硬,所以我们就来解析下代码:

/**
 * 
 */
package com.cxm;

/**
 * @author admin
 *
 */
public class HeapSort
{
	/** *以2为底的对数 *
	 * @paramparam 
	 * *@return 
	 * */
	private static double getLog(double param){ 
		return Math.log(param)/Math.log(2); 
	}
	
	private static void print(int[]data){  
		int pre=-2;  
		for(int i=0;i<data.length;i++){ 
			if(pre<(int)getLog(i+1)){
				pre=(int)getLog(i+1); 
//				System.out.println(); 
			} 
			System.out.print(data[i]+ " "); 
		} 
	}
	
	/** *排序,最大值放在末尾,data虽然是最大堆,
	 * 在排序后就成了递增的 *@paramdata 
	 **/
	private static void heapSort(int[]data){ 
		//末尾与头交换,交换后调整最大堆 
		for(int i=data.length-1;i>0;i--){ 
			int temp=data[0]; 
			data[0]=data[i]; 
			data[i]=temp; 
			maxHeapify(data,i,0); 
		} 
	}
	
	/** *创建最大堆 *
	 * @paramdata 
	 * *@paramheapSize
	 * 需要创建最大堆的大小,一般在sort的时候用到,因为最多值放在末尾,末尾就不再归入最大堆了 
	 *@paramindex当前需要创建最大堆的位置 
	*/
	private static void maxHeapify(int[]data,int heapSize,int index){//4,1
		//当前点与左右子节点比较 
		int left=getChildLeftIndex(index);//3
		int right=getChildRightIndex(index);//4  
		int largest=index;//1
		if(left<heapSize&&data[largest]<data[left]){ 
			largest=left; //3
		} 
		if(right<heapSize&&data[largest]<data[right]){ 
			largest=right; 
		} 
//		System.out.println("index is : "+index +" left is : "+ left + " right is : "+right+" largest is : "+largest);
		//得到最大值后可能需要交换,如果交换了,其子节点可能就不是最大堆了,需要重新调整 
		if(largest!=index){ 
			int temp=data[index]; 
			data[index]=data[largest]; 
			data[largest]=temp; 
			maxHeapify(data,heapSize,largest); 
		} 
	}
	
	private static int[] sort= new int[100001];
	private static int j = 0 ;
	
	static {
		for(int i =0;i<=100000;i++){
			sort[j]=i;
			j++;
		}
	}
 
	private static void buildMaxHeapify(int[]data){
		//没有子节点的才需要创建最大堆,从最后一个的父节点开始 
		int startIndex=getParentIndex(data.length); //4
		//从尾端开始创建最大堆,每次都是正确的堆
		for(int i=startIndex;i>=0;i--){ 
			maxHeapify(data,data.length,i); //4,1
		} 
	}
	
	/** *右子节点position 
	 *@paramcurrent 
	 **@return 
	 **/
	private static int getChildRightIndex(int current){ 
		return(current<<1)+2; 
	} 

	/** *左子节点position注意括号,加法优先级更高 *
	 * @paramcurrent *@return 
	 **/
	private static int getChildLeftIndex(int current){ 
		return(current<<1)+1; 
	} 
	
	/** *父节点位置 *@paramcurrent *@return */
	private static int getParentIndex(int current){ 
		return(current-2)>>1; 
	}
	
	//插入排序
	public static void insertion_sor(int[]data){ 
		int j = 0;
		int curData;
		for(int i =1;i<data.length;i++){
			curData = data[i];
			j=i-1;
			while((j>=0)&&curData<data[j]){
				data[j+1]=data[j];
				j--;
			}
			data[j+1]= curData;
		}
	}
	
	public static void main(String[]args){ 
		Long before = System.currentTimeMillis();
//		insertion_sor(sort);
		buildMaxHeapify(sort); 
		heapSort(sort);
		Long after = System.currentTimeMillis();
		System.out.println(after-before);
//		print(sort);
		
	}  
}
	


堆排序的概念:

例如{3,1,2,4,6,9,7,8,10} 首先对这个序列建一个堆:

 

通过简单的规律我们可以看出整个树的最后一个子树的父节点是数组长度的     (array.length-2)>>1;

最后的子树在数组3,而他的左右枝分别为7和8。

从下标3开始递减给每个子树进行最大堆重建。

下标3 : 4比8小,8比9小,所以4和10换位置。因为4和10换了位置,可能会影响原来10位置下的树的正确性,所以要对现在4以及下面可能出现的树进行重新建树。

下标2 :2比9小,9比7大,所以2和9换位置。同理需要对下调的数以及下面的树进行最大树重建。

下标1 :1比10小,10比6大,所以1和10换位置。

 

    同时由于1下调导致1现在的位置可能不满足最大堆,所以要重建1所在的子树:

    

 

下标0 :  10比3大,10比9大,所以3和10换位置:

 

重复上面给的下调重建的步骤,最终得到的最大堆为:

那么数组的第一个数就是整个数组的最大数,下面就从下标第一位到最后一位重建最大堆,一次类推。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值