选择排序——堆排序

前提知识:

若以一维数组存储一个堆,则堆对应一棵完全二叉树,且所有非叶结点的值均不大于(或不小于)其子女的值,根结点(堆顶元素)的值是最小(或最大)的。

小顶堆:{12,36,24,85,47,30,53,91}

大顶堆:{96, 83,27,38,11,09}

如果i>1,则双亲是结点[i/2]。也就是说下标i与2i和2i+1是双亲子女关系。 当排序对象为数组时,下标从0开始,所以下标 i 与下标 2i+1和2i+2是双亲子女关系。

最后一个有孩子节点的节点是(length-1)/2

升序排序:用大顶堆

降序排序:用小顶堆

基本思想:

先将数组建成一个大顶堆;然后再将大顶堆的根放到数组的最后一个位置;然后调整此时的堆成大顶堆,重复,直至到根。

操作过程:

从算法描述来看,堆排序需要两个过程,一是建立堆,二是堆顶与堆的最后一个元素交换位置。所以堆排序有两个函数组成。一是建堆的渗透函数,二是反复调用渗透函数实现排序的函数。

public class heapSort {

	/*调整大顶堆
	 * @parm 数组
	 * @parm 要调整的位置
	 * @parm 数组的长度
	 */
	public void heapAdjust(int a[],int s,int length){
		int temp = a[s];
		int child = 2*s+1;//左孩子的位置;右孩子位置是2*s+2
		while(child < length){
			if(child+1 < length && a[child]<a[child+1]){
				++child;//找到左右孩子中,较大的那一位
			}
			if(a[s]<a[child]){
				//比较a[s]和较大的孩子,a[s]>a[child],则不交换;否则,交换
				a[s]=a[child];// 重新设置s ,即待调整的下一个结点的位置
				s=child;
				child = 2*s+1;
			}else{
				break;
			}
			a[s]=temp;//最后将调整的值,赋值给最后a[s]调整到的位置
		}
	}
	//生成堆
	public void createHeap(int a[],int length){
		//最后一个有孩子的节点位置是(length-1)/2
		for(int i=(length-1)/2;i>=0;--i){
			heapAdjust(a,i,length);
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int a[]={3,5,2,9,7,1,4};
		int n=a.length;
		heapSort hs = new heapSort();
		hs.createHeap(a,n);
		for(int i=n-1;i>=0;--i){
			//先把最后一个元素和大顶堆的根交换
			int temp=a[i];
			a[i]=a[0];
			a[0]=temp;
			//再调整堆
			hs.heapAdjust(a, 0, i);
		}
		for(int i=0;i<n;i++){
			System.out.println(a[i]);
		}
	}
	
}

分析:

设树深度为k,。从根到叶的筛选,元素比较次数至多2(k-1)次,交换记录至多k 次。所以,在建好堆后,排序过程中的筛选次数不超过下式: 

                               

而建堆时的比较次数不超过4n 次,因此堆排序最坏情况下,时间复杂度也为:O(nlogn )。


感觉堆排序比较难理解,关键是要有数据结构堆的知识掌握


参考资料:http://blog.csdn.net/hguisu/article/details/7776068
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值