堆是一棵被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。这样的树称为完全二叉树。完全二叉树的高度为logN下取整。在堆中,对于每一个节点X,X的parent中的关键字小于(或等于)X中的关键字,根节点除外。
堆的插入操作:为将一个元素插入到堆中,在下一个可用位置创建一个空穴,如果插入的元素可以放入空穴中而并不破坏堆的序,那么插入完成。否则把空穴的父节点上的元素移入空穴中,这样空穴就朝着根的方向上冒一步,继续该过程直到该元素能被放入空穴为止,这种一般策略叫作上滤。
删除堆的最小元:当删除一个最小元时,要在根节点建立一个空穴。由于现在的堆少了一个元素,因此堆中最后一个元素必须移动到该堆的某个地方。如果最后一个元素可以被放到空穴中,那么删除最小元完成。否则,将空穴的两个child中较小者移入空穴中,这样就把空穴向下推了一层,重复该步骤直到最后一个元素可以被放入空穴中。这等价于将最后一个元素置入沿着根开始包含最小儿子的一条路径上的一个正确的位置。这种一般的策略叫作下滤。
#ifndef BINARY_HEAP_H
#define BINARY_HEAP_H
#include "dsexceptions.h"
#include <vector>
using namespace std;
template <typename Comparable>
class BinaryHeap
{
public:
explicit BinaryHeap(int capacity = 100)
: array(capacity + 1), currentSize{
0 } {
}
explicit BinaryHeap(const vector<Comparable> & items)
: array(items.size() + 10), currentSize{
items.size() }
{
for (int i = 0; i < items.size(); ++i)
array[i + 1] = items[i];
buildHeap();
}
bool isEmpty() const
{
return currentSize == 0;
}
const Comparable & findMin() const
{
if (isEmpty())
throw UnderflowException{
};
return array[1];
}
void insert(const Comparable & x)
{
if (currentSize == array.size() - 1)
array.resize(array.size() * 2);
int hole = ++currentSize;
Comparable copy = x;
array[0] = std::move(copy);
for (; x < array[hole / 2]; hole /= 2)
array[hole] = std::move(array[hole / 2]);
array[hole] = std::move(array[0]);
}
void insert(Comparable && x)
{
if (currentSize == array.size() - 1)
array.resize(array.size() * 2);
int hole = ++currentSize;
Comparable copy = x;
array[0] = std::move(copy);
for (; hole > 1 && x < array[hole / 2]; hole /= 2)
array[hole] = std::move(array[hole / 2]);
array[hole] = std::move(x);
}
void deleteMin()
{
if (isEmpty())
throw UnderflowException{
};
array[1] = std::move(array[currentSize--]);
percolateDown(1);
}
void deleteMin(Comparable & minItem)
{
if (isEmpty())
throw UnderflowException{
};
minItem = std::move(array[1]);
array[1] = std::move(array[currentSize--]);
percolateDown(1);
}
void makeEmpty()
{
currentSize = 0;
}
private:
int currentSize;
vector<Comparable> array;
void buildHeap()
{
for (int i = currentSize / 2; i > 0; --i)
percolateDown(i);
}
void percolateDown(int hole)
{
int child;
Comparable tmp = std::move(array[hole]);
for (; hole * 2 <= currentSize; hole = child) {
child = hole * 2;
if (child != currentSize && array[child + 1] < array[child])
++child;
if (array[child] < tmp)
array[hole] = std::move(array[child]);
else
break;
}
array[hole] = std::move(tmp);
}
};
#endif