package cn.com.dom4j.sort;
import java.util.Arrays;
public class Test2 {
/**
* 堆排序
*/
public static <AnyType extends Comparable<? super AnyType>> void heapSort(AnyType[] a) {
// buildHeap
for (int i = a.length / 2; i >= 0; i--) {
// 将数组值按初始顺序放入堆中, 从根节点执行下滤操作将构建一个堆
percolateDown(a, i, a.length);
}
// deleteMax
for (int i = a.length - 1; i > 0; i--) {
// 在构建了一个 max堆后, 将根节点与最后一个元素互换, 同时将堆的大小 -1, 调整位置, 再次实现堆序
// 这样每互换一次, 最大的元素就会放在堆的后面 (已经从堆中删除, 不属于堆了), 堆后面的元素会保持顺序, 直到堆中只剩一个元素为止
swap(a, 0, i);
percolateDown(a, 0, i);
}
}
/**
* 下滤操作: 调整某个节点的位置, 以保持堆序
* @param a 待排序序列
* @param i 要调整的节点在数组中的索引
* @param n 堆的大小 (堆中元素个数)
*/
private static <AnyType extends Comparable<? super AnyType>> void percolateDown(AnyType[] a, int i, int n) {
int child;
AnyType tmp;
// tmp记录被调整元素的值, i的值随 child不断改变, 直到比较完所有的子节点 (leftChild(i) < n) 为止
for (tmp = a[i]; leftChild(i) < n; i = child) {
child = leftChild(i);
// child == n - 1时, 其左子节点为堆的最后一个元素, 没有右节点, 无须比较
// 将该节点与其左右节点比较, 记录其中最小的节点的索引
if (child != n - 1 && a[child].compareTo(a[child + 1]) < 0) {
child++;
}
// 将需要被调整和节点与其子节点进行比较, 如果小于子节点, 当前节点的值替换为子节点的值 (注意不是交换)
if (tmp.compareTo(a[child]) < 0) {
a[i] = a[child];
} else {
break;
}
}
// 找到合适的位置后, 直接赋值来避免多余的交换操作
a[i] = tmp;
}
/**
* 获取某个节点的左子节点在数组中的索引, 因为是从 0开始的, 所以要 +1
*/
private static int leftChild(int i) {
return 2 * i + 1;
}
/**
* 交换数组中两个元素的位置
*/
public static <AnyType extends Comparable<? super AnyType>> void swap(AnyType[] arr, int i, int j) {
if (arr == null || arr.length <= 1 || i == j) {
return;
}
AnyType tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}