升序
堆排序可以认为是选择排序的一种优化
时间复杂度是O(NlogN),不稳定
核心思想
- 对序列进行原地建堆(heapify)。
-
将第一个元素与最后一个元素交换位置(大顶堆,交换堆顶元素和堆尾元素)。
-
堆的元素减一。
-
对堆顶进行一次siftdown操作
- 重复上面2~4步,直到堆元素只剩1个。
时间复杂度 : 步骤1 O(n) +步骤5 O(n-1)* 步骤2~4 O(1+1+logn)= O(n)+O(nlogn)=O(nlogn)
代码实现
public class HeapSort extends Sort {
private int heapSize;
@Override
protected void sort() {
// 原地建堆
heapSize=array.length;
for (int i = (heapSize >> 1) - 1; i >= 0; i--) {
siftDown(i);
}
while (heapSize > 1) {
//交换对顶元素和尾部元素,heapSize--
swap(0, --heapSize );
//对0位置siftDown,恢复堆的性质
siftDown(0);
}
}
private void siftDown(int index) {
Integer element = array[index];
int half = heapSize >> 1;
while (index < half) { // index必须是非叶子节点
// 默认是左边跟父节点比
int childIndex = (index << 1) + 1;
Integer child = array[childIndex];
int rightIndex = childIndex + 1;
// 右子节点比左子节点大
if (rightIndex < heapSize &&
cmp(array[rightIndex], child) > 0) {
child = array[childIndex = rightIndex];
}
// 大于等于子节点
if (cmp(element, child) >= 0) break;
array[index] = child;
index = childIndex;
}
array[index] = element;
}
}
写了个demo测试了冒泡,选择和堆排序的效率输出结果如下:
【HeapSort】
耗时:0.001s(1ms) 比较:1.69万 交换:999
------------------------------------------------------------------
【BubbleSort】
耗时:0.007s(7ms) 比较:21.52万 交换:13.87万
------------------------------------------------------------------
【SelectionSort】
耗时:0.007s(7ms) 比较:49.95万 交换:999
------------------------------------------------------------------
Process finished with exit code 0
可以看到 选择排序和堆排序元素交换的次数是一样的。
堆排序是不稳定排序,由于是 原地建堆所以空间复杂度是O(1)
参考:小码哥的恋上数据结构第二期