算法描述
是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
在堆的数据结构中,堆中的最大值总是位于根节点(在优先队列中使用堆的话堆中的最小值位于根节点)。
堆中定义以下几种操作:
最大堆调整:将堆的末端子节点作调整,使得子节点永远小于父节点
创建最大堆:将堆中的所有数据重新排序
堆排序:移除位在第一个数据的根节点,并做最大堆调整的递归运算
图解
参考代码
public class HeapSort {
public static void main(String[] args) {
// int[] arr = {49, 38, 65, 97, 76, 13};
int[] arr = new int[20];
Random random = new Random();
for (int i = 0; i < arr.length; i++) {
arr[i] = random.nextInt(50);
}
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
//升序排序
public static int len;
private static void heapSort(int[] arr) {
len = arr.length;
// 1.将传入的数组堆化
heapify(arr);
// 2.将最大值与最后一个元素交换 交换完成在堆化
for (int i = arr.length - 1; i > 0; i--) {
exchange(arr, 0, i);
len--;
heapify(arr);
}
}
// 堆化
private static void heapify(int[] arr) {
for (int i = len - 1; i >= 0; i--) {
siftDown(arr, i);
}
}
// 下沉操作
private static void siftDown(int[] arr, int i) {
// 造成最大堆
while (leftChild(i) < len) {
int bigChild = leftChild(i);
if ( bigChild+ 1 < len && arr[bigChild] < arr[bigChild + 1]) {//左右孩子进行比较
bigChild = rightChild(i);
}
if (arr[bigChild] > arr[i]) {//左右孩子进行比较结果中大的,再与其父节点进行比较
exchange(arr, bigChild, i);
i = bigChild; //重新更新父节点角标(下沉就要下沉到底)
} else {
break;
}
}
}
// 数组存储二叉树 left child(i)=2*i+1 right child(i)=2*i+2 parent(i)=(i-1)/2
private static int parent(int i) {
return (i - 1) / 2;
}
private static int leftChild(int i) {
return i * 2 + 1;
}
private static int rightChild(int i) {
return i * 2 + 2;
}
private static void exchange(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
算法性能
-
时间复杂度
O(nlogn)
-
空间复杂度
O(1)
-
算法稳定性
不稳定