算法导论第四版ch6中文笔记与最大堆的c++实现
作者:Claude Du
本文文字内容和图片基本来源于算法导论第四版第6章。
堆排序的时间复杂度与并归排序一样, 空间复杂度与插入排序同样有空间原址性。堆排序是集合了并归排序与插入排序两者优点的一种排序算法,其使用了称为“堆”的数据结构,该数据结构不仅可以用于堆排序,还可以构造有效的优先队列。
6.1 堆
堆:堆是一个数组,可以看成一个近似的完全二叉树
一个节点的父节点,左孩子和右孩子的相应下标,对应关系如下代码所示,相应图示如图6.1:
// the index of this MaxHeap follows the convention of the Introduction to Algorithm Chap6
// which means the root of a maxHeap is maxHeap[0] instead of maxHeap[1],
// and the last element of a maxHeap is maxHeap[heapSize] instead of maxHeap[heapSize - 1]
inline size_t PARENT(size_t x) {
return x / 2;
}
inline size_t LEFT(size_t x) {
return x * 2;
}
inline size_t RIGHT(size_t x) {
return x * 2 + 1;
}
最大堆的性质: A [ P A R E N T ( i ) ] ≥ A [ i ] A[PARENT(i)] \geq A[i] A[PARENT(i)]≥A[i]
最小堆的性质: A [ P A R E N T ( i ) ] ≤ A [ i ] A[PARENT(i)] \leq A[i] A[PARENT(i)]≤A[i]
如果把堆看成一棵树,那么堆中某一节点的高度:该节点到叶结点的最长简单路径上边的数目。堆上的一些基本操作的运行时间基本和树的高度成正比。
接下来要介绍的是堆上的一些核心基本操作过程,并说明如何在排序算法和优先队列中应用它们:
6.2 维护最大堆的性质
6.3 构造最大堆
6.4 堆排序
6.5 利用堆实现优先队列
6.2 维护最大堆的性质
MaxHeapify是用于维护最大堆性质的重要过程。在任何时候调用MaxHeapify时,我们假定根节点为LEFT(i) 和RIGHT(i)的二叉树都是最大堆。
MaxHeapify 通过不断让vec_[i]在堆中“逐层下降”,从而使得以下标i为根节点的子树再次遵循最大堆的性质。
MAX-HEAPIFY c++代码实现如下:
template <typename T> class MaxHeap {
private:
vector<T> vec_;
size_t heapSize = 0;
size_t size = 0;
// recursion version of MaxHeapify, personally don't like it
void MaxHeapify(size_t i) {
size_t left = LEFT(i);
size_t right = RIGHT(i);
size_t largest = i;
if (left <= heapSize && vec_[left] > vec_[largest]) largest = left;
if (right <= heapSize && vec_[right] > vec_[largest]) largest = right;
if (largest == i) return;
// exchange vec_[i] with vec_[largest]
T temp = vec_[i];
vec_[i] = vec_[largest];
vec_[largest] = temp;
MaxHeapify(largest);
}
void BuildMaxHeap();
public:
MaxHeap(vector<T> vec): vec_(vec){
if (vec.size() < 1) std::cerr << "the size of Heap is smaller than one" << st