堆:可视为一棵完全二叉树结构,最小堆每个父节点都小于孩子结点,最大堆每个父节点都大于孩子结点。
建堆思想:实现向下调整算法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; }