【数据结构与算法】堆排序

1、堆的性质
堆是一棵完全二叉树,除最后一层外每层都是满的(元素个数为2^(i-1),根节点为第1层),最后一层如果不满则只缺少右边叶结点。如果按照广度优先,即从上至下,从左至右对节点编号。根节点序号为0,节点i的父节点是(i-1)/2,左子节点是2*i+1。最小堆中任意父节点不能比子节点大,最大堆中任意父节点不能比子节点小。

	private static int getParent(int i){
		return (i-1)/2;
	}
	private static int getLeftChild(int i){
		return 2*i+1;
	}

2、最小堆的调整规则
如果将最小堆中的顶点替换成某一个数,若这个数仍然比它的左右子节点小,则整个结构仍然是最小堆。否则将此节点与左右子节点中较小的节点发生交换,只有较小子节点所在的子树需要调整

	//递回方法,不推荐
	private static void adjustChildMinHeap(int[] almostHeapExceptCur,int cur,int last){
		int left=getLeftChild(cur);
		if(left>last) return;
		int min=left;
		//找出左右子节点中较小的节点
		if(left<last&&almostHeapExceptCur[left+1]<almostHeapExceptCur[left]) min=left+1;
		//如果较小的子节点比当前节点更小,则需要替换并调整这一子树
		if(almostHeapExceptCur[min]<almostHeapExceptCur[cur]){
			swap(almostHeapExceptCur, min, cur);
			// 继续调整较小子节点所在子树
			adjustChildMinHeap(almostHeapExceptCur,min,last);
		}
	}
	// 非递归方法,almostHeapExceptCur数组中从pos+1到last位置已经是最小堆
	private static void adjustChildMinHeap(int[] almostHeapExceptCur,int pos,int last){
		//实际上pos元素只需移动到它最后应在位置,无需每次都移动,item函数中不变
		int item = almostHeapExceptCur[pos];
		//当前调整的节点位置,cur每次迭代后可能发生变化
		int cur =pos;
		//默认左子节点较小
		int min = getLeftChild(cur);
		while(min<=last){
			//如果有右子节点,则比较两个子节点的值,min取较小节点的位置
			if(min<last && almostHeapExceptCur[min+1]<almostHeapExceptCur[min]){
				min = min+1;
			}
			//如果较小子节点比当前节点更小,则其所在子树需要调整。
			if(almostHeapExceptCur[min]<item){
				//将较小子节点上移到当前节点位置,相当于较小子节点位置已经为空。
				almostHeapExceptCur[cur]=almostHeapExceptCur[min];
				//下一次从min位置开始调整,且填充min位置元素
				cur = min;
				min = getLeftChild(cur);
			}else{
				break;
			}
		}
		almostHeapExceptCur[cur] = item;
	}

3、最小堆的建立
对于一个数组nums[N],建立规则是从最后往前按照规则调整结构使后面满足最小堆的性质。实际上,没有子节点的叶节点是无须调整的,即我们可以从getParent(N)节点开始调整。

	private static void initMinHeap(int[] nums){
		for(int i=getParent(nums.length-1);i>=0;i--){
			adjustChildMinHeap(nums,i,nums.length-1);
		}
	}

4、利用最小堆排序
因为最小堆的性质,根节点是堆中最小的。我们可以每次将根节点取出来放入已排序序列。同时堆结构被破坏,根节点没有值,我们可以将最后一个节点放入根节点,也就是交换根节点与最后节点,然后继续调整结构使之成为最小堆。

	public static void minHeapSortToDes(int[] nums){
		initMinHeap(nums);
		int last=nums.length-1;
		while(last>0){
			swap(nums, 0, last);
			adjustChildMinHeap(nums,0,--last);			
		}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值