时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn),最坏情况下也为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
空间复杂度:
O
(
1
)
O(1)
O(1)
/**
* 堆排序
*
* @author PengHao
* @date 2020-4-2 10:42:34
*/
public class HeapSort {
/**
* @param a 待排序数组
*/
public static void heapSort(int[] a) {
// 建大顶堆,索引从0开始,最后一个非叶子结点索引为a.length/2-1
for (int i = (a.length >> 1) - 1; i >= 0; --i) {
heapAdjust(a, i, a.length);
}
for (int i = a.length - 1; i > 0; --i) {
int temp = a[0];
a[0] = a[i];
a[i] = temp;
heapAdjust(a, 0, i);
}
}
/**
* 堆调整
*
* @param a 待调整的数组
* @param from 起始索引,包含
* @param to 结束索引,不包含
*/
private static void heapAdjust(int[] a, int from, int to) {
// 区间[from, to)构成一个子树
// 保存子树的根结点值
int key = a[from];
// 每次进入for循环,i指向from结点的左子结点
for (int i = (from << 1) + 1; i < to; i = (i << 1) + 1) {
// 如果from结点有右子结点,并且右子结点大于左子结点,将i指向右子结点
if (i + 1 < to && a[i] < a[i + 1]) {
++i;
}
// 如果子结点的最大值小于from结点的值说明子树已经是大顶堆,不用交换
if (a[i] <= key) {
break;
}
// 将from结点和i结点交换,注:其实未交换,只进行了赋值,key的妙用
a[from] = a[i];
// 更新from结点,即from向下移动
from = i;
}
// 最后一个from结点值为key,使用key的目的是避免for循环中的交换,节约时间
a[from] = key;
}
}