堆排序(七)

import java.util.Arrays;
/**
 * 
 * @author lixuwu
 *堆排序两步:建立堆的过程,堆的调整过程
 *堆中的元素用数组来进行存储,标号从1开始;结点i的左右子树为2i和2i+1,堆的最后一个非叶结点的编号为n/2
 *堆的大小即为堆中元素的个数,不等于数组的大小(这里在堆得调整过程中很重要)
 *对于堆的存储结构数组,第一个元素的下标为0,一般用一个特殊的数字区分,不参与堆的排序过程
 */
public class HeapSort {
	/**
	 * 
	 * @param array
	 * @param i	需要调整的堆元素在数组中的位置。一般从堆顶(1)或者堆的堆的最后一个非叶节点(n/2)开始
	 * @param n	堆的大小,也就是堆中存储元素的个数
	 * 
	 * 以下向下调整的过程是建立一个大顶堆的过程,从堆中某一个位置i开始,分别与他的左右子树(2i,2i+1)进行比较,
	 * 找出i,2i,2i+1中最大的元素t,如果最大元素t=i,结束调整。如果最大元素t !=i,则两者数值交换,i=t,继续向下调整
	 */
	public static void siftdown(int array[],int i,int n){
		int t,temp,flag=0;	//flag用来标记是否需要继续向下调整
		
		//当i结点有儿子(其实是至少有左儿子)并且需要继续调整的时候循环就执行
		while(i*2<=n && flag==0){
			//首先判断它和左儿子的关系,并用t记录较大结点编号
			if(array[i] < array[2*i]){
				t = 2*i;
			}else{
				t = i;
			}
			
			//如果结点i有右儿子,再对右儿子进行讨论,如果右儿子的值更大,更新较大的结点t
			if(i*2+1 <=n){
				if(array[t] <array[i*2+1])
					t = i*2+1;		
			}
			
			//如果发现最大的结点编号不是自己,说明子结点中有比父结点更大的。此时将父结点与子结点进行交换
			if(t != i){
				temp = array[i];
				array[i] = array[t];
				array[t] = temp;
				i = t;	//更新i为刚才与它交换的儿子结点的编号,便于接下来继续向下调整
			}else{
				flag = 1;	//否则说明当前的父结点已经比两个子结点都要大了,不再进行调整了
			}
		}	//end while;
	}

	//建立堆的函数
	public static void creat(int array[]){
		int i;
		int n = array.length-1;	//因为堆的第一个结点编号从1开始,所有要排除数组中下标为0的那个元素
		//从最后一个非叶结点n/2到第1个依次进行向下调整的过程
		for(i=n/2;i>=1;i--)	
			siftdown(array, i,n);
	}
	
	//堆排序:从大顶堆开始,每次将堆顶元素与堆尾元素交换,堆的大小减一,然后再调整堆顶元素。如此反复
	//直到堆的大小变为1为止。此时数组中的元素就已经是排序好的了
	public static void heapSort(int array[]){
		int n = array.length-1;		//表示堆中元素的个数
		while(n>1){
			int temp = array[1];
			array[1] = array[n];
			array[n] = temp;
			n--;
			siftdown(array, 1,n);
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a[] ={0,2,4,1,5,3,9,7,8,6};
		creat(a);
		heapSort(a);
		System.out.println(Arrays.toString(a));
		

	}

}

运行结果:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

posted @ 2015-09-12 16:18  CS408  阅读(292)  评论(0编辑  收藏  举报