二叉堆的定义

二叉堆是完全二叉树或者是近似完全二叉树。

二叉堆满足二个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆。

下面这段代码实现了数组实现一个最小堆的过程,包括构造堆,堆的插入、删除操作。具体细节会在注释中给出解释。

MinHeap.hpp

#pragma once
#include<iostream>
using namespace std;
#include<vector>
template<class T>
class MinHeap{
public:
 MinHeap()
 {}
 MinHeap(const T* array, size_t size){
  //将数组元素逐个插入到vector里
  for (int i = 0; i < size; i++){
   _array.push_back(array[i]);
  }
  //计算最后一个非叶子结点,并从这个结点开始调整
  int begin = _array.size() / 2 - 1;
  for (; begin >= 0; begin--){
   _AdjustDown(begin);
  }
 }
 MinHeap(vector<T>& array){
  //将数组元素逐个插入到vector里
  for (int i = 0; i < array.size(); i++){
   _array.push_back(array[i]);
  }
  
  //计算最后一个非叶子结点,并从这个结点开始调整
  int begin = _array.size() / 2 - 1;
  for (; begin >= 0; begin--){
   _AdjustDown(begin);
  }
 }
 void Insert(const T& x){
  _array.push_back(x);            //插入结点
  _AdjustUp(_array.size() - 1);    //重新调整
 }
 void RemoveHeapTop(){
  //检查堆中是否还有元素
  if (_array.size() == 0){
   cout << "empty array" << endl;
   return;
  }
  
  //将最后一个结点的值给第一个结点,并删除最后一个结点
  _array[0] = _array[_array.size() -1];
  _array.pop_back();         
  _AdjustDown(0);       //重新调整
 }
protected:
 void _AdjustDown(int root){
  //计算结点的左右节点的下标
  int left = root * 2 + 1;
  int right = left + 1;
  //检查root是否为叶子结点,是否产生越界
  while (left < _array.size()){
   //找出左右结点中的最小值,并与父结点交换
   int min = left;
   if (right < _array.size() && _array[left] > _array[right])
    min = right;
   if (_array[min] < _array[root]){
    swap(_array[root], _array[min]);
    //继续调整直到满足小堆条件
    root = min;
    left = root * 2 + 1;
    right = left + 1;
   }
   else
    break;
  }
 }
 void _AdjustUp(int child){
  //计算插入结点的父结点
  int root = (child - 1) / 2;
  //一直向上调整直到根结点的值小于左右结点
  while (root > 0){
   if (_array[child] < _array[root]){
    swap(_array[child], _array[root]);
    child = root;
    root = (child - 1) / 2;
   }
   else
    break;
  }
  if (_array[child] < _array[root] && root == 0)
   swap(_array[child], _array[root]);
 }
private:
 vector<T> _array;
};

这里的向上调整和向下调整函数可以实现对堆的处理。向上调整用于插入之后的排序,要注意循环条件和边界值的部分。

这里的测试用例二实现了对一个vector类对象的构造

main.cpp

#include<iostream>
using namespace std;
#include"MinHeap.hpp"
#include<vector>
void test1(){
 int arr[10] = { 10, 16, 18, 11, 12, 13, 15, 17, 14, 19 };
 int size = sizeof(arr) / sizeof(arr[0]);
 MinHeap<int> hp1(arr,size);
 hp1.Insert(9);
 hp1.Insert(7);
 hp1.RemoveHeapTop();
 hp1.RemoveHeapTop();
 hp1.RemoveHeapTop();
}
void test2(){
 int array[10] = { 10, 16, 18, 11, 12, 13, 15, 17, 14, 19 };
 vector<int> arr;
 for (int i = 0; i < 10; i++){
  arr.push_back(array[i]);
 }
 MinHeap<int> hp2(arr);
 hp2.Insert(9);
 hp2.Insert(7);
 hp2.RemoveHeapTop();
 hp2.RemoveHeapTop();
 hp2.RemoveHeapTop();
}
int main(){
 test1();
 test2();
 return 0;
}