java堆排序工具包_java实现堆排序

package com.crazy.leetcode;

import java.util.Arrays;

/**

* 堆排序(大顶堆)

*/

public class HeapSort {

/**

* 初始无序数组

*/

private int[] nums;

/**

* nums数组长度

*/

private int length;

/**

* 堆末已排好序的节点数量

*/

private int orderCount;

/**

* 对数组升序排序

* @param nums 无序数组

*/

private void heapSort(int[] nums) {

this.nums = nums;

length = nums.length;

orderCount = 0;

buildHeap();

adjustHeap();

}

/**

* 构造大顶堆

*/

private void buildHeap() {

// 找到最后一个非叶子节点,从右到左,从下到上遍历到根节点,对每个节点进行调整

// 文末会解释为什么最后一个非叶子节点的下标是length / 2 - 1

for (int i = length / 2 - 1; i >= 0; i--) {

adjustNode(i);

}

}

/**

* 调整堆:

* 1.交换根节点与最后一个节点(不包括已排好序的节点)

* 2.堆末已排好序的节点数量 + 1

* 3.对未排好序的部分,构造大顶堆

* 4.重复以上步骤,直到已排好序的节点数量 = 总节点数

*/

private void adjustHeap() {

while (orderCount < length) {

swap(0, length - 1 - orderCount);

orderCount ++;

for (int i = (length - orderCount) / 2 - 1; i >= 0; i--) {

adjustNode(i);

}

}

}

/**

* 调整节点:若左节点或右节点大于当前节点,把当前节点与左右节点中较大者交换

* @param i 当前节点下标

*/

private void adjustNode(int i) {

// 当前节点的值

int curVal = nums[i];

// 左节点的值

int leftVal = nums[2 * i + 1];

// 右节点不为空

if (2 * i + 2 < length - orderCount) {

// 右节点的值

int rightVal = nums[2 * i + 2];

if (rightVal > leftVal && rightVal > curVal) {

// 交换当前节点和右节点

swap(i, 2 * i + 2);

return;

}

}

if (leftVal > curVal) {

// 交换当前节点和左节点

swap(i, 2 * i + 1);

}

}

/**

* 交换元素

* @param i 元素i

* @param j 元素j

*/

private void swap(int i, int j) {

int temp = nums[i];

nums[i] = nums[j];

nums[j] = temp;

}

}

验证

public static void main(String[] args) {

int[] nums = new int[]{4, 6, 8, 5, 9, 11, 13, 3, 5, 17};

new HeapSort().heapSort(nums);

System.out.println(Arrays.toString(nums));

}

[3, 4, 5, 5, 6, 8, 9, 11, 13, 17]

堆排序中,需要求最后一个非叶子节点的下标,公式为nums.length / 2 - 1,证明如下:

已知堆为完全二叉树,完全二叉树有以下特性:序号(从0开始)为i的节点,其左节点序号为2i+1,其右节点序号为2i+2

设最后一个非叶子节点序号为i,总节点数为n,层数为k,分两种情况讨论

1.最后一个非叶子节点没有右节点,即左节点序号为2 * i + 1,该节点同时是整个树最后一个节点,即2 * i + 1 = n,得出i = (n - 1) / 2,这种情况下,前k - 1层的节点数2 ^ (k - 1) - 1是奇数,最后一层也是奇数,所以n一定是偶数,所以 (n - 1) / 2 = n / 2 - 1

2.最后一个非叶子节点有右节点,即右节点序号为2 * i + 2,该节点同时是整个树最后一个节点,即2 * i + 2 = n,得出i = (n - 2) / 2,这种情况下,前k - 1层的节点数2 ^ (k - 1) - 1是奇数,最后一层是偶数,所以n一定是奇数,所以 (n - 2) / 2 = n / 2 - 1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值