堆的定义
-
堆是一颗完全二叉树;
-
堆中某个节点的值总是不大于(或不小于)其父节点的值
其中,我们把根节点最大的堆叫做大顶堆,根节点最小的堆叫做小顶堆。
堆的存储结构
数组
siftdown
siftdown又称为堆调整,以大顶堆siftdown为例,即将左右子树中较大者的值与父节点的值对换,递归进行该过程,使得以当前节点为根的子树满足arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
heapify
从树的第一个非叶节点开始往前遍历,对每一个非叶节点执行堆调整,使得整棵树满足arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
siftup时间复杂度相对siftdown更高,本文暂不介绍siftup以及基于siftup的heapify,详情可参考siftup与siftdown的时间复杂度
步骤
构造堆
- 给定如下无序数组
- 此时我们从最后一个非叶子结点开始(arr.length/2-1=5/2-1=1),从左至右,从下至上进行调整。
- 找到第二个非叶节点4,由于[4,9,8]中9元素最大,4和9交换。
- 这时,交换导致了子树[4,5,6]结构混乱,继续调整,[4,5,6]中6最大,交换4和6。
堆调整
将堆顶元素与末尾元素交换,并对新的堆顶元素进行堆调整
- 将堆顶元素9和末尾元素4进行交换
- 从堆顶开始重新siftdown,使其继续满足堆定义
- 再将堆顶元素8与末尾元素5进行交换,得到第二大元素8.
- 后续过程,继续进行调整,交换,如此反复进行,最终使得整个序列有序
代码
//Java 代码实现
public class HeapSort{
public int[] sort(int[] sourceArray) throws Exception {
// 对arr进行拷贝,不改变参数内容
int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);
int len = arr.length;
heapify(arr, len);
// 最大值拿出来,放到堆的最后一位,然后对长度为len-1的堆重新siftdown
for (int i = len - 1; i > 0; i