堆排序代码

堆排序的基本三步走:
1、将无序序列构造为堆结构,如果是升序排序则为 大顶堆,降序则为 小顶堆。(这里使用大顶堆)
2、将 堆顶元素 与 堆尾元素进行交换(即,把当前最大元素 “沉” 入到 堆尾)
3、重新构造堆结构,构造堆结构的目的就是将未排序序列的最大值 “抬” 到堆顶。(但是要注意,此时我们已经把一个最大值成功排序到堆尾了,因此我们应当排除掉已经排序好的元素。 我们可以用 len 来表示当前序列还未排序的序列长度,每次交换完 堆顶 和 堆尾 元素后 len–,然后重新构造堆结构时,如果当前元素下标大于 len 则排除掉该元素,即该元素不参与堆的重新构造)
终止条件:这样 每一次重新构造堆结构,我们都会把一个未排序序列中的最大值排列到堆尾,因此,对于一个长度为 n 的无序序列,只需要重构 n - 1 次堆结构即可(因为对于最后一个元素而言,当它前面的元素都排序完毕时,它也就自动排序完了)
在这里插入图片描述

private static void HeapSort(int[] nums) {
	// 安全判断
	if (nums == null || nums.length == 0) return;
	// 构建大顶堆
	BuildHeap(nums);
	// 每一次重构顶堆,都会把当前的最大值给沉到堆尾,即排序完一个当前最大值
	// 而最后一个当前最大值就不需要排序了(即最小值), 因为前面排完,最后一个就自动确定了
	// 所以要排完整个长度为n的序列, 需要重构顶堆n - 1次
	int len = nums.Length - 1;
	for (int i = nums.Length - 1; i > 0; i--) {
		// 交互堆顶与堆尾, 把当前最大值沉到最小面
		Swap(nums, 0, i);
		// 因为每重构一次,当前最大值都会被沉到当前的最后一层
		// 所以每重构一次,要len--, 防止最大值又被重构到最顶层
		Heapify(nums, 0, len--);
	}
}

private static void BuildHeap(int[] nums) {
    //第一个非叶子结点的下标是 nums.Length / 2 - 1
    // // 从数组中最后一个 非叶子节点开始向前遍历
	int start = nums.Length / 2 - 1;
	for (int i = start; i >= 0; i--) {
		Heapify(nums, i, nums.Length);
	}
}
private static void Heapify(int[] nums, int i, int len) {
	// 计算当前非叶子节点的左右节点索引
	int left = 2 * i + 1;
	int right = 2 * i + 2;
	// 默认当前节点是最大值
	int largestIndex = i;
	// 如果有左节点,且左节点比当前节点大,则更新最大值的索引
	if (left < len && nums[left] > nums[largestIndex]) largestIndex = left;
	if (right < len && nums[right] > nums[largestIndex]) largestIndex = right;
	if (largestIndex != i) {
		// 如果当前节点比它的子节点小, 则交换位置
		Swap(nums, largestIndex, i);
		// 交换位置后子节点的值就变化了(子节点的值,变成了原来当前节点值)
		// 所以要判断子节点(当前节点的子节点也是非叶子节点的情况)
		Heapify(nums, largestIndex, len);
	} 
}

private static void swap(int[] nums, int i, int j) {
	nums[i] ^= nums[j];
	nums[j] ^= nums[i];
	nums[i] ^= nums[j];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值