PriorityQueue.h //优先级队列基于"堆"(内嵌双向链表)的实现,此时入队和出队的时间复杂度都为O(lgn), // 复制、清空和遍历队列的时间复杂度为O(n) //另外还有一种实现方法是基于"数组"的实现, 此时入队的时间复杂度为O(1),出队的时间复杂度为O(n) //从时间复杂度上讲:基于"堆"(内嵌双向链表)的实现具有优势。 //从空间复杂度上讲:基于"堆"(内嵌双向链表)的实现这种方法中,每个节点需要5个指针,占20个字节。 // 这就需要根据存储数据的大小来计算空间复杂度,并与基于"数组"的实现这种方法比较! //所有数据结构的实现都是基于"数组"或者"链表"或者"树"或者"图" ; template <class DT> struct PQNode{ DT info; PQNode<DT> *left; //指向左子结点 PQNode<DT> *right; //指向右子结点 PQNode<DT> *parent; //指向双亲 PQNode<DT> *back; //指向双向链表中的上一个结点 PQNode<DT> *next; //指向双向链表中的下一个结点 }; template <class DT> class PriorityQueue { public: PriorityQueue(); PriorityQueue(const PriorityQueue<DT> &appq); ~PriorityQueue(); PriorityQueue<DT> & operator=(const PriorityQueue<DT> &rpq); void enqueue(DT &newElement); //在队尾插入 bool dequeue(DT &deqElement); //队头出队 bool isEmpty(); void makeEmpty(); private: PQNode<DT> rootHeader; //根结点,实际根作为跟头的唯一右子结点 PQNode<DT> *root; //指向根结点 PQNode<DT> *last; //指向最后一个结点 PQNode<DT> *lastParent; //指向最后一个"双亲"结点,也即last的双亲 bool left; //判断lastParent是不是可以移向链表中的下一个结点,left=false表示最后一个子结点为左子结点 inline void insertNode(const DT &inf); //在优先队列的末尾插入元素 //堆排序的时间复杂度为O(nlgn) inline void heapify(PQNode<DT> *current); //"堆化",前提是current的子树是一个堆 inline void deepCopy(const PriorityQueue<DT> &original); //"深复制" }; PriorityQueue.cpp #include "PriorityQueue.h" template<class DT> PriorityQueue<DT>::PriorityQueue() { last = lastParent = root = &rootHeader; root->next = NULL; left = false; } template<class DT> PriorityQueue<DT>::PriorityQueue(const PriorityQueue<DT> &appq) { deepCopy(appq); } template<class DT> PriorityQueue<DT>::~PriorityQueue() { makeEmpty(); } template<class DT> PriorityQueue<DT>& PriorityQueue<DT>::operator =(const PriorityQueue<DT> &rpq) { if(this == &rpq) //重载"="操作符,需要做此判断 return *this; makeEmpty(); deepCopy(rpq); return *this; } template<class DT> void PriorityQueue<DT>::enqueue(DT &newElement) { //在优先队列的末尾插入元素 insertNode(newElement); //把插入的元素放到优先队列的适当位置 PQNode<DT> *current = last; PQNode<DT> *parent = current->parent ; while(parent != root && newElement > parent->info) { current->info = parent->info ; current = parent; parent = current->parent; } current->info = newElement; } template<class DT> bool PriorityQueue<DT>::dequeue(DT &deqElement) { if(root == last) return false; PQNode<DT> *current = root->right ; //实际根作为跟头的唯一右子结点 deqElement = current->info ; //把优先队列中的最后一个结点的元素放到实际根结点中,然后删除最后一个结点,然后实施"堆化" current->info = last->info ; if(left) { lastParent = lastParent->back; lastParent->right = NULL; } else lastParent->left = NULL; last = last->back; delete last->next; last->next = NULL; left = !left; if(root != last) heapify(current); return true; } template<class DT> bool PriorityQueue<DT>::isEmpty() { return root == last; } template<class DT> void PriorityQueue<DT>::makeEmpty() { while(root != last) { lastParent = last->back; //这里只是借lastParent用做临时指针而已,也可以另外定义一个指针作为tempPtr delete last; last = lastParent; } root->next = NULL; left = false; } template <class DT> inline void PriorityQueue<DT>::insertNode(const DT &inf) { last->next = new PQNode<DT>; last->next->back = last; last = last->next; last->left = last->right = last->next = NULL; //每插入一个Node,需要维护Node结点的4个指针和一个info last->parent = lastParent; if(left) //如果lastParent的左子结点为空,则插入到左子结点。 lastParent->left = last; else { lastParent->right = last; lastParent = lastParent->next; //如果插入到右子结点,"最后双亲"指针向下移 } last->info = inf; left = !left; } template <class DT> inline void PriorityQueue<DT>::heapify(PQNode<DT> *current) {//从curent开始,从左往右,从上往下,把current->info和current的子结点中大的元素进行交换 DT temp = current->info ; PQNode<DT> *leftc = current->left ; PQNode<DT> *rightc = current->right ; PQNode<DT> *largest; largest = (rightc == NULL) ? leftc : ((leftc->info > rightc->info) ? leftc : rightc); //考虑只有左子结点的情况 while((leftc != NULL) && largest->info > temp) //结束条件为:current没有左子结点啦 { current->info = largest->info; current = largest; leftc = largest->left; rightc = largest->right; largest = (rightc == NULL) ? leftc : ((leftc->info > rightc->info) ? leftc : rightc); } current->info = temp; } template <class DT> inline void PriorityQueue<DT>::deepCopy(const PriorityQueue<DT> &original) { //初始化一个根结点 last = lastParent = root = &rootHeader; root->next = NULL; left = false; //调用insertNode构造优先级队列,因为original本身是优先级队列,从而可以只调用insertNode,而不需要"堆化" PQNode<DT> *originalptr = original.root->next; for( ;originalptr != NULL; originalptr = originalptr->next) insertNode(originalptr->info); } 测试用例: #include<iostream> #include "PriorityQueue.cpp" using namespace std; int main() { PriorityQueue<int> PQobj; int a[10] = {5,4,12,34,9,0,5,13,7,6}; for(int ix=0;ix<10;++ix) PQobj.enqueue(a[ix]); //初始化一个优先级队列 PriorityQueue<int> PQobj1(PQobj); //测试复制构造函数 PriorityQueue<int> PQobj2 = PQobj; //测试重载"="操作符 int deqElement(0); for(int ix=0;ix<10;++ix) { PQobj1.dequeue(deqElement); cout<<deqElement<<","; } cout<<endl; if(PQobj1.isEmpty()) cout<<"PQobj1 is empty"<<endl; PQobj2.makeEmpty(); if(PQobj2.isEmpty()) cout<<"PQobj2 is empty"<<endl; return 0; }