堆是一棵被完全填满的二叉树,底层上的元素从左到右填入,这样的树称为完全二叉树。
一棵高为h的完全二叉树右2^h到2^(h+1) - 1 个结点。完全二叉树的树高为logN。
A
/ \
B C
/ \ / \
D E F G
/ \ /
H I J
_________________________________________________
|_ _| _A_ |_B_|_C_|_D_|_E_|_F_|_G_|_H_|_I_|_J_|_ _|_ _|_ _|
0 1 2 3 4 5 6 7 8 9 10 11 12 13
对于数组中任意位置 i 上的元素,其左儿子在位置2i上,右儿子在(2i + 1)上。它的父亲则在[i / 2] 上。
一个堆数据结构由一个数组和一个表示当前大小的证书组成。
下面的实现代码分为 BinaryHeap.h 和 main.cpp.
模板编程分文件写编译器支持不一,所以一般在一个文件内实现。
BinaryHeap.h
#ifndef __BINARY_HEAP_H
#define __BINARY_HEAP_H
#include <iostream>
#include <vector>
#include <exception>
#include <cstdlib>
using std::vector;
using std::cout;
using std::endl;
using namespace std;
class UnderflowException : public exception
{
public :
UnderflowException() : exception()
{
cout << "underflow\n";
exit(0);
}
};
template <typename T>
class BinaryHeap
{
public:
explicit BinaryHeap(int capacity = 100);
explicit BinaryHeap(const vector<T> & items);
~BinaryHeap();
bool isEmpty() const;
const T & findMin() const;
void insert(const T &x);
void deleteMin();
void deleteMin(T & minItem);
void makeEmpty();
T minimum() const;
void print() const;
private:
int currentSize; // number of elements in heap
vector<T> array; // the heap array
void buildHeap();
void percolateDown(int hole);
};
template <typename T>
BinaryHeap<T>::BinaryHeap(int capacity)
: array(capacity + 10)
{
currentSize = 0;
}
template <typename T>
BinaryHeap<T>::BinaryHeap(const vector<T> & item)
: array(item.size() + 10), currentSize(item.size())
{
for(int i = 0; i < item.size(); ++i)
{
array[i+1] = item[i];
}
buildHeap();
}
template <typename T>
BinaryHeap<T>::~BinaryHeap()
{
makeEmpty();
// (array).swap(array); // 匿名对象,来释放空间
array.shrink_to_fit(); // -std=c++11
cout << "array.capacity() " << array.capacity() <<endl;
cout << "~BinaryHeap()" << endl;
}
/**
* Establish heap order property from an arbitrary arrangement of items.
* Runs in linear time. O(n)
*/
template <typename T>
void BinaryHeap<T>::buildHeap()
{
for(int i = currentSize / 2; i > 0; --i)
percolateDown(i);
}
template <typename T>
void BinaryHeap<T>::makeEmpty()
{
currentSize = 0;
array.clear();
}
template <typename T>
T BinaryHeap<T>::minimum() const
{
if(isEmpty())
throw UnderflowException();
return array[1];
}
template <typename T>
void BinaryHeap<T>::print() const
{
for(int i = 1 ; i <= currentSize; ++i)
cout << array[i] << " ";
cout << endl;
}
template <typename T>
inline bool BinaryHeap<T>::isEmpty() const
{
return currentSize == 0;
}
/*
* Insert item x, allowing duplicates
*/
template <typename T>
void BinaryHeap<T>::insert(const T &x)
{
if(currentSize == array.size() - 1)
{
array.resize(array.size() * 2);
}
int hole = ++currentSize;
for( ; hole > 1 && x < array[hole / 2]; hole /= 2)
{
array[hole] = array[hole / 2];
}
array[hole] = x;
}
/*
* Remove the minimum item.
* Throws UnderflowException if empty.
*/
template <typename T>
void BinaryHeap<T>::deleteMin()
{
if(isEmpty())
throw UnderflowException();
array[1] = array[currentSize--];
percolateDown(1);
}
/*
* Remove the minimum item and place it in minItem.
* Throws UnderflowException if empty.
*/
template <typename T>
void BinaryHeap<T>::deleteMin(T & minItem)
{
if(isEmpty)
throw UnderflowException();
minItem = array[1];
array[1] = array[currentSize--];
percolateDown(1);
}
template <typename T>
void BinaryHeap<T>::percolateDown(int hole)
{
int child;
T tmp = array[hole];
for( ; (hole << 2) <= currentSize; hole = child)
{
child = hole << 2; // hole * 2
if(child != currentSize && array[child + 1] < array[child])
child++;
if(array[child] < tmp)
array[hole] = array[child];
else
break;
}
array[hole] = tmp;
}
#endif // #ifndef __BINARY_HEAP_H
main.cpp
#include <iostream>
#include "BinaryHeap.h"
using namespace std;
int main(int argc, char **argv)
{
BinaryHeap<int> bHeap;
cout << (bHeap.isEmpty() ? "empty" : "not empty") << endl;
//bHeap.deleteMin(); // exception: the Heap is empty
bHeap.insert(10);
bHeap.insert(2);
bHeap.insert(5);
bHeap.insert(13);
bHeap.insert(1);
bHeap.insert(8);
cout << "minimum " << bHeap.minimum() << endl;
bHeap.print();
bHeap.deleteMin();
bHeap.print();
BinaryHeap<int> bHeap2(bHeap);
cout << "bHeap2" << endl << " ";
bHeap2.print();
return 0;
}
makefile非常非常简单,
# 2015-11-15
# Summer
#object = main.o
main :
g++ -std=c++11 main.cpp -o main
#main.o: BinaryHeap.h
#g++ -std=c++11 -c main.o main.cpp BinaryHeap.h
.PHONY: clean
clean:
rm -rf $(object)
cleanAll:
rm -r main $(object)
不想写mekefile也可以的,编译时输入
g++ -std=c++11 main.cpp -o main
即可
输出内容:
empty
minimum 1
1 2 5 13 10 8
8 2 5 13 10
bHeap2
8 2 5 13 10
array.capacity() 0
~BinaryHeap()
array.capacity() 0
~BinaryHeap()
以上内容参考《数据结构与算法分析C++描述》。