堆:可视为一棵完全二叉树结构,最小堆每个父节点都小于孩子结点,最大堆每个父节点都大于孩子结点。
建堆思想:实现向下调整算法AdjustDown():即当一个节点的左子树和右子树都已为最大堆或最小堆(在这里则寻找树倒着走的第一个非叶子结点,依次进行调整),比较其左右孩子结点满足大堆或小堆要求的节点,再与此节点比较,若孩子结点大,满足大堆交换两节点值,或小堆,孩子结点小则交换。大堆与小堆思想基本相同,所以实现用仿函数进行实现。
建堆完成后可在堆中实现在尾部插入和删除头节点等操作,从中又实现一个向上调整算法AdjustUp(),其类似于向下调整算法.
优先级队列:则在大堆与小堆基础上实现队列的优先级等系列操作。
代码实现:
#include <iostream>
#include <cstdlib>
#include <vector>
#include <assert.h>
using namespace std;
template <class T> //仿函数
struct Less
{
bool operator()(const T& l1,const T& l2)
{
return l1<l2;
}
};
template <class T>
struct Greater
{
bool operator()(const T& l1,const T& l2)
{
return l1>l2;
}
};
template <class T,class Compare=Greater<T>>
class Heap
{
public:
Heap()
{}
Heap(T* a,size_t n)
:_a(a,a+n)
{
for(int i=(n-2)/2;i>=0;--i) //先找到树的第一个非叶子结点
{
_AdjustDown(i); //向下调整
}
}
void Push(const T& x)
{
_a.push_back(x);
_AdjustUp(_a.size()-1); //向上调整
}
void Pop()
{
assert(_a.size());
swap(_a[0],_a[_a.size()-1]);
_a.pop_back();
_AdjustDown(0); //向下调整
}
const T& Top()
{
assert(_a.size());
return _a[0];
}
size_t Size()
{
return _a.size();
}
bool Empty()
{
return _a.empty();
}
protected:
void _AdjustDown(size_t root) //向下调整
{
Compare compare;
size_t parent=root;
size_t child=parent*2+1;
while(child<_a.size()) //当parent不为叶子结点
{
if(child+1<_a.size()&&compare(_a[child+1],_a[child]))//比较左右孩子符合条件的
++child;
if(compare(_a[child],_a[parent])) //比较孩子和父节点
{
swap(_a[parent],_a[child]);
parent=child;
child=parent*2+1;
}
else
break;
}
}
void _AdjustUp(size_t child) //向上调整
{
Compare compare;
size_t parent=(child-1)/2;
while(child>0)
{
if(compare(_a[child],_a[parent])) //比较孩子和父节点
{
swap(_a[parent],_a[child]);
child=parent;
parent=(child-1)/2;
}
else
break;
}
}
protected:
vector<T> _a;
};
template <class T,class Compare=Greater<T>>
class PriorityQueue //优先级队列
{
public:
void Push(const T& x)
{
_hp1.Push(x);
}
void Pop()
{
_hp1.Pop();
}
const T& Top()
{
return _hp1.Top();
}
size_t Size()
{
return _hp1.Size();
}
bool Empty()
{
return _hp1.Empty();
}
protected:
Heap<T,Compare> _hp1; //用堆实现
};
void TestHeap()
{
//最大堆
int a1[]={10,11,13,12,16,18,15,17,14,19};
Heap<int> hp1(a1,sizeof(a1)/sizeof(a1[0]));
hp1.Push(20);
hp1.Pop();
//最小堆
int a2[]={19,17,18,14,16,13,15,12,10,11};
Heap<int,Less<int>> hp2(a2,sizeof(a2)/sizeof(a2[0]));
hp2.Push(9);
hp2.Pop();
}
void TestPriorityQueue()
{
PriorityQueue<int> que;
que.Push(10);
que.Push(11);
que.Push(13);
que.Push(12);
que.Push(16);
que.Push(18);
que.Push(15);
que.Push(17);
if(!que.Empty())
{
cout<<que.Size()<<endl;
cout<<que.Top()<<endl;
}
que.Pop();
}
int main()
{
TestHeap();
TestPriorityQueue();
system("pause");
return 0;
}