【排序】堆排序(Heam Sort)

堆排序(Heap Sort)

原理:将数组构造成一个大顶锥,此时根节点就是最大值,然后将根节点值与末尾值交换,然后将剩余的n-1个元素重新构造成大顶锥,得到次最大值,如此反复执行即可
大顶锥:完全二叉树,节点值大于等于左右孩子,所以根节点是最大值。当前节点下标i,那么做孩子为2i,右孩子为2i+1。
堆调整函数思想:当前节点与左右孩子比较,取较大值进行交换。。然后向下比较子树。。最后使得当前节点的值为其子树中的最大值
构建完整大顶锥思想:找到序列的所有节点(有孩子),然后按照从下往上,从右往左的顺序(也就是树的层序遍历反过来)对所有节点进行堆调整,这样得到一个完整的大顶锥
时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
import java.util.Arrays;
public class test {
	public static void HeapSort(int[] nums) {
		int i;
		//将一个序列,调整为一个大顶锥的完整过程
		//1、注意,这里是对所有的节点(有孩子的)调用堆调整函数。最终形成一个大顶锥
		//2、下面的排序过程是在原来大顶锥的基础上进行了一个交换
		//3、所以只有根节点这一个节点是不符合大顶锥定义(根节点大于左右孩子)的
		//4、所以只需要调用一次HeapAdjust就行了
		for (i = nums.length/2 - 1; i >= 0; i--) {
			HeapAdjust(nums, i, nums.length - 1);
		}
		//正式的排序过程
		for (i = nums.length - 1; i > 0; i--) {
			//将堆顶的数字后最后一个数字交换,也就是将最大的数字放大最后
			swap(nums, 0, i);
			//将剩下的数字(除去最后一个最大的数字)重新调整为大顶锥
			HeapAdjust(nums, 0, i-1);
		}
		
	}
	//堆调整函数
	//将数组nums中数字s....m调整为一个大顶锥,这样第一个数字就是当前序列中的最大值
	public static void HeapAdjust(int [] nums, int s, int m) {
		int temp, j;
		temp = nums[s];
		//当前节点s,左孩子为2*s,右孩子为2*s+1,然后孩子的孩子。。酱紫,所以j更新为2*s
		for(j = 2*s; j <= m; j*=2) {
			//如果左孩子<右孩子,那么j+1,这个时候j就指向了右孩子
			//为什么呢?因为我们的目标是找到孩子中的较大值
			if(j < m && nums[j] < nums[j+1]) j++;
			//如果父节点>左右孩子,那么直接跳出了。。。符合大顶锥的定义
			if (temp >= nums[j]) break;
			//将找到的较大的孩子赋值给父节点
			nums[s] = nums[j];
			//将父节点的下标更新为孩子节点
			s = j;
		}
		//将原来父节点的值赋值给子节点,实现交换
		nums[s] = temp;
	}
	
	//交换
	public static  void swap(int [] nums, int i, int j) {
		int temp = nums[i];
		nums[i] = nums[j];
		nums[j] = temp;
	}
	public static void main(String[] args) {
		int [] nums = {9, 1, 5, 8, 3, 7, 4, 6, 2};
		HeapSort(nums);
		System.out.println(Arrays.toString(nums));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值