堆 是具有以下性质的完全二叉树:
每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;
每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。堆排序的基本思想是:
将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。一般升序采用大顶堆,降序采用小顶堆。
核心代码:
public static void heapSort(int[] arr) {
//初始化调整堆
for(int i = arr.length / 2; i >= 0; i--) {
adjustHeap(arr,i,arr.length);
}
for(int i = arr.length-1; i > 0; i--) {
swap(arr,0,i);
adjustHeap(arr,0,i);
}
}
/**
* 调整堆
* @param arr
* @param parent
* @param length 未排序的序列长度
*/
private static void adjustHeap(int[] arr,int parent,int length) {
int temp = arr[parent]; //保存当前父节点的值
int child = parent * 2 + 1; //获得该父节点的左孩子的索引
while(child < length) {
//如果存在右孩子 且 右孩子的值比左孩子大,取右孩子索引
if(child + 1 < length && arr[child + 1] > arr[child]) {
++child;
}
//如果父节点的值大于孩子的值,直接结束
if(temp > arr[child]) {
break;
}
//否则把最大孩子的值赋给父节点
arr[parent] = arr[child];
//从该节点的左孩子开始继续向下调整堆
parent = child;
child = child * 2 + 1;
}
arr[parent] = temp;
}
/**
* 交换数组元素
* @param arr
* @param a
* @param b
*/
private static void swap(int[] arr,int a,int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
堆排序是一种选择排序,它是一种不稳定的排序算法,它的最坏,最好,平均时间复杂度均为O(nlogn).