C++ 最小堆实现

最小堆特征

最小堆是一棵完全二叉树,其父节点的值,是左右子树的最小值。通常使用数组来实现:

  • 树的根为Arr[0]
  • 对于其他 i 节点,则有其他公式:
公式 返回值
Arr[(i-1)/2] 返回 i 节点的父节点
Arr[(2*i)+1] 返回 i 节点的左孩子
Arr[(2*i)+2] 返回 i 节点的右孩子

最小堆类定义

先看最小堆的class 定义声明,我们使用数组实现最小堆

class MinHeap
{
private:
    int *harr; // pointer to array of elements in heap
    int capacity; // maximum possible size of min heap
    int heap_size; // Current number of elements in min heap
public:
    MinHeap(int capacity);
    int GetParent(int i) { return (i-1)/2; }
    int GetLeftChild(int i) { return (2*i + 1); }
    int GetRightChild(int i) { return (2*i + 2); }
    int IsEmpty() {return heap_size > 0; }
    int GetRoot() { return harr[0]; }
    void PushBack(int k)
    void Pop();
private:
    void MinHeapify(int i);
    // 交换第 i 和第 j 元素值
    void Swap(int i, int j);
};

构造函数直接设定堆的最大存储空间:

MinHeap::MinHeap(int cap)
{
    heap_size = 0;
    capacity = cap;
    harr = new int[capacity];
}

接下来我们主要实现堆的追加元素和弹出元素:

void MinHeap::Swap(int i, int j)
{
	int temp = harr[i];
	harr[i] = h[j];
	h[j] = temp;	
}
// 直接将追加元素添加到数组末尾,然后再做堆平衡
void MinHeap::PushBack(int k)
{
    if (heap_size == capacity) {
        cout << "Overflow: Could not insertKey"<< endl;
        return;
    }
    heap_size++;
    int i = heap_size - 1;
    harr[i] = k;
    // Fix the min heap property if it is violated
    while (i != 0 && harr[parent(i)] > harr[i]) {
        Swap(i, parent(i));
        i = parent(i);
    }
}

// 弹出根元素
void MinHeap::Pop() {
	if (heap_size <= 0) {
		return;
	}
	if (heap_size == 1) {
		heap_size--;
		return harr[0];
	}
	// 直接将树底元素作为新的根,然后找到根、左孩子、右孩子的最小元素,swap后,递归平衡下去
	harr[0] = harr[heap_size-1];
	heap_size--;
	MinHeapify(0);
	return;
}
// 递归平衡最小堆
// 假设i节点的左子树和右子树都是平衡的
void MinHeap::MinHeapify(int i) 
{ 
    int left = GetLeftChild(i); 
    int right = GetRightChild(i); 
    int smallest = i;
    if (left < heap_size && harr[left] < harr[smallest]) 
        smallest = left; 
    if (right < heap_size && harr[right] < harr[smallest]) 
        smallest = right; 
    if (smallest != i) {
        Swap(i, smallest); 
        MinHeapify(smallest); 
    } 
}

最大堆的实现也是类似,只需要把其中父子间比较大小的操作反向即可。
上面的实现对于通常的最大堆,最小堆已经足够使用。但是如果还需要实现下沉(Sink)和上浮操作,可以如下实现:


你可能感兴趣的:(Algorithms,二叉树,算法,树堆)