ヒープは完全に塗りつぶされたバイナリツリーです。可能な例外は下のレイヤーで、下のレイヤーの要素は左から右に塗りつぶされます。このようなツリーは、完全なバイナリツリーと呼ばれます。完全なバイナリツリーの高さは、logNに切り捨てられます。ヒープでは、各ノードXについて、Xの親のキーは、ルートノードを除いて、Xのキーより小さい(または等しい)です。
ヒープ挿入操作:要素をヒープに挿入するために、次の使用可能な位置にキャビティが作成されます。挿入された要素をヒープの順序を壊さずにキャビティに挿入できれば、挿入は完了です。それ以外の場合は、穴の親ノードの要素を穴に移動して、穴がルートに向かってステップし、要素を穴に配置できるようになるまでプロセスを続行します。この一般的な戦略はフィルタリングと呼ばれます。
ヒープの最小要素を削除する:最小要素を削除するときは、ルートノードに穴を作成します。現在のヒープには1つの要素がないため、ヒープの最後の要素をヒープ内のどこかに移動する必要があります。最後の要素をキャビティに配置できる場合は、最小の要素を削除して完了します。それ以外の場合は、キャビティの2つの子のうち小さい方をキャビティに移動して、キャビティを1レベル下に押し、最後の要素をキャビティに配置できるまでこの手順を繰り返します。これは、ルートからの最小の息子を含むパスに沿って、最後の要素を正しい位置に配置することと同じです。この一般的な戦略は、ダウンフィルタリングと呼ばれます。
#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