思路
将数组看成二叉堆,如果是从小到大排序,先下沉为最大堆。再将堆顶的数(最大的数)逐轮与最后一个数交换并不将它纳入堆中,然后下沉。这样一来,每轮都能在数组最后得到这轮中最大的数。
代码
public class HeapSort{
public static void heapSort(int[] arr) {
//构建最大二叉堆
//从最后一个非叶子节点开始下沉
for(int i = (arr.length - 2)/2; i>=0; i--){
downAdjust(arr , i, arr.length);
}
//从最后一个节点开始,与根节点交换,然后下沉
for(int i = arr.length - 1; i > 0; i--){
int tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
downAdjust(arr , 0, i);
}
}
private static void downAdjust(int[] arr, int parent, int length) {
int pValue = arr[parent];
//左孩子位置
int child = 2 * parent + 1;
while(child < length){
//如果有右孩子且右孩子更大,怎选择这个孩子
if(child + 1 < length && arr[child+1] > arr[child])
child ++;
if(pValue >= arr[child])
break;
//child上浮
arr[parent] = arr[child];
//parent下沉,暂时不改变值
parent = child;
child = 2 * child + 1;
}
//改变值
arr[parent] = pValue;
}
public static void main(String[] args){
int[] array = new int[]{5,5,8,6,6,3,9,2,1,4,7,1,2};
heapSort(array);
System.out.println(Arrays.toString(array));
}
}
复杂度分析
时间复杂度
构建二叉堆 O(n),n-1 次交换下沉 O(nlogn),共 O(n)
空间复杂度
额外空间与数组长度无关
O(1)
稳定性分析
涉及大范围内交换,不稳定
优势
相比快速排序,时间复杂度稳定在 O(nlogn),不会到 O(n2),而且空间复杂度是 O(1)。
但实际上,若快速排序不考虑极端情况,还是比堆排序快。因为堆排序的时间复杂度毕竟是 O(n + nlogn)。
适用场景
无需稳定性、数据量大