堆ADT
堆是一种类似于完全二叉树的结构。堆可以用完全二叉树的图来表示,但是堆通常来说都是由数组来进行构建的。相较于指针传输,数组下标传输更快,因此通过构建最小堆和最大堆就能够快速找到最小或最大最优先的元素。唯一的问题在于堆的最大高度要提前确定。
1.堆的性质
最小堆:在一个堆中,对于每一个结点X,X的父节点的data小于X的data,X的data小于任一子结点的data。
最大堆:在一个堆中,对于每一个结点X,X的父节点的data大于X的data,X的data大于任一子结点的data。
(根节点除外)
2.建一个最小二叉堆
----------------------------------------------------堆的框架及接口---------------------------------------------------
#include<queue>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
template<typename T>
class BinaryHeap
{
public:
explicit BinaryHeap(int capacity=100);
explicit BinaryHeap(const vector<T>& items);
bool isEmpty()const;
const T& FindMin()const;
void Insert(const T& data);
void DeleteMin();
void DeleteMin(T& minItem);
void MakeEmpty();
int currentsize;
~BinaryHeap()
private:
vector<T> array;
void BuildHeap();
void PercolateDown(int hole);
};
通过使用stl函数vector建立可变容量数组
----------------------------------------------------构造函数---------------------------------------------------------
template<typename T>
BinaryHeap<T>::BinaryHeap(const vector<T>& items) :array(items.size() + 10), currentsize(items.size())
{
for (int i = 0; i < items.size(); i++)
{
array[i + 1] = items[i];
BuildHeap;
}
}
template<typename T>
void BinaryHeap<T>::BuildHeap()
{
for (int i = currentsize/2; i >0; i--)
{
PercolateDown(1);
}
}
插入堆
template<typename T>
void BinaryHeap<T>::Insert(const T& data)
{
if (currentsize ==array.size()-1)
{
array.resize(array.size() * 2);
}
int hole = ++currentsize;
for ( ;hole>1&&data<array[hole/2]; hole/2)
{
array[hole] = array[hole / 2];
array[hole] = data;
}
}
删除最小
template<typename T>
void BinaryHeap<T>::DeleteMin()
{
if (isEmpty())
{
throw underflowException;
array[1] = array[currentsize--];
PercolateDown(1);
}
}
template<typename T>
void BinaryHeap<T>::DeleteMin(T& minitem)
{
if (isEmpty())
{
throw underflowException;
minitem = array[1];
array[1] = array[currentsize--];
PercolateDown(1);
}
}
渗滤percolate down
template<typename T>
void BinaryHeap<T>::PercolateDown(int hole)
{
int child;
T tmp = 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] = array[child];
}
else
{
break;
}
array[hole] = tmp;
}
}
3.优先队列的应用
null
4.d堆
相较于二叉堆,d堆所有的子结点都有d个儿子。
d堆的insert运行时间更短为log_d(N),但是delete运行时间更长为dlog_d(N).
在实践中4堆可以胜过二叉堆。
普通的堆难以实行合并merge的操作,实行merge操作繁琐且运行时间过长。以下几种特殊堆可以执行merge。
5.左式堆
左式堆也是二叉树,与二叉堆唯一区别是左式堆非常不平衡。
零路径长(null path length):从X到不具有两个儿子结点特征的结点的最短路径长。具有0/1个儿子结点npl=0,npl(NULL)=-1。
左式堆:对于每一个结点X,左儿子的npl大于等于右孩子的npl。
#include<iostream>
template<typename T>
class LeftistHeap
{
public:
LeftistHeap();
LeftistHeap(const LeftistHeap& rhs);
~LeftistHeap();
bool isEmpty()const;
const T& findMin()const;
void insert(const T& x);
void deleteMin();
void deleteMin(T& minItem);
void makeEmpty();
void merge(LeftistHeap& rhs);
const LeftistHeap& operator=(const LeftistHeap& rhs);
private:
struct LeftistNode
{
T element;
LeftistNode* leftchild;
LeftistNode* rightchild;
int npl;
LeftistNode(const T&theElement,LeftisNode*lt=NULL,LeftisNode*rt=NULL,int np=0):element(theElement),leftchild(lt),rightchild(rt),npl(np){ }
};
LeftistNode* root;
LeftistNode* merge(LeftisNode* h1, LeftisNode* h2)
{
if (h1==NULL)
{
return h2;
}
if (h2==NULL)
{
return h1;
}
if (h1->element<h2->element)
{
return merge1(h1, h2);
}
if (h1->element>h2->element)
{
return merge1(h2, h1);
}
}
LeftistNode* merge1(LeftisNode* h1, LeftisNode* h2)
{
if (h1->leftchild == NULL)
{
h1->left = h2;
}
else
{
h1->rightchild = merge(h1->rightchild, h2);
if (h1->leftchild->npl < h1->rightchild->npl)
{
swapChildren(h1);
h1->npl = h1->right->npl + 1;
}
}
retrun h1;
}
void swapChildren(LeftistNode* t);
void reclaimMemory(LeftisNode* t);
LeftistNode* clone(LeftisNode* t) const;
};
template<typename T>
LeftistHeap<T>::LeftistHeap()
{
LeftisNode<T>* p;
T data;
cin >> data;
if (data==NULL)
{
p = null;
}
else
{
p = new LeftisNode<T>();
if (p==NULL)
{
cout << "false";
exit(1);
}
}
p->element = data;
p->leftchild = NULL;
p->rightchild =NULL
}
template<typename T>
LeftistHeap<T>::LeftistHeap(const LeftistHeap& rhs)
{
}
template<typename T>
LeftistHeap<T>::~LeftistHeap()
{
reclaimMemory();
}
template<typename T>
inline void LeftistHeap<T>::insert(const T& x)
{
root = merge(new LeftistNode(x), root);
}
template<typename T>
void LeftistHeap<T>::swapChildren(LeftistNode* t)
{
LeftistNode<T>* AUX;
AUX = t->rightchild;
t->rightchild = t->leftchild;
t->leftchild = AUX;
return t;
}
template<typename T>
void LeftistHeap<T>::merge(LeftistHeap& rhs)
{
if (this==&rhs)
{
return;
}
root = merge(root, rhs.root);
rhs.root = NULL;
}
template<typename T>
void LeftistHeap<T>::deleteMin(T& minItem)
{
minItem = findMin();
deleteMin();
}
6.斜堆
7.二项队列
一个二项队列是堆序的树的集合。堆序中的每一棵树都是被约束的二项树。高度为k的二项树将通过一棵二项树k-1连接到另一棵二项树的根上。