堆的基本概念不在此介绍,各位看官自行百度。由于堆的特性导致堆可以用数组进行模拟,所以堆排序其实是在数组(即堆)上进行排序的过程,在所有堆的操作中,都离不开一个操作:调整堆,该过程使堆保持堆的性质(大堆或小堆的性质)。在介绍堆排序之前必要要介绍如何创建堆,由于堆是使用数组保存的,所有我的理解是,建堆的过程就是堆化数组,即使给定的数组具有堆的性质。堆化的过程其实就是调整堆的过程,我们把调整堆的过程定义成一个单独的函数void AdjustHeap(int heap[], int root_index, int heap_length),参数分别是代表堆的数组,要调整的堆的根节点在数组中的下标,注意是下标,建议读者自己画个图模拟调整堆的过程。第三个参数是堆的长度,在这里就让他等于数组的长度,其实可以不相等。
调整堆的过程如下:
1.根据根节点下标,确定左右子节点的下标。
2.找出根节点和左右子节点中最小值的下标,注意该过程要判断边界,即左右子节点的下标是否超出堆的长度。
3.如果最小值的下标等于根节点的下标,函数返回。
4.否则,交换把根节点与最小值交换,由于交换可能破坏了最小值所在子树的对性质,所以递归调用AdjustHeap函数。
那么现在还有一个问题,就是堆化的时候,从哪个节点开始调整堆呢?这个也是建堆的关键,我们可以这样想,子节点已经是堆了,无需在调整了,所以我们没必要从最后一个节点开始调整,一般是从(heap_length/2)开始调节,一直到下标1为止(堆的下标一般