概念
优先级队列是0个或多个元素的集合,每个元素都有一个优先权值。在最小优先级队列中,查找和删除的元素都是优先级最小的元素;在最大优先级队列中,查找和删除的元素都是优先级最大的元素。优先级队列元素可以有相同的优先级,这时候查找与删除可以按任意顺序处理。
抽象类:
template<class T>
class maxPriorityQueue
{
public:
virtual ~maxPriorityQueue() {}
virtual bool empty() const=0;//返回true,当且仅当队列为空
virtual int size() const=0;//返回队列的元素个数
virtual const T& top()=0;//返回优先级最大的元素的引用
virtual void pop()=0;//删除队首元素
virtual void push(const T& theElement)=0;//插入元素theElement
};
堆
定义
一棵大根树(小根树)是这样的一棵树:其中每个结点的值都大于(小于)或等于其子节点(如果有)的值。
一个大根堆(小根堆)既是大根数(小根树)也是完全二叉树。
大根堆的插入
把新元素插入最后一个位置的新节点,然后沿着从新节点到根节点的路径,执行一趟起泡操作,将新元素与其父节点的元素比较交换,知道后者大于或等于前者为止。
template<class T>
void maxHeap<T>::push(const T& theElement)
{
//将theElement插入大根堆
//必要时增加数组长度
if(heapSize==arrayLength-1)
{
//数组长度加倍
changeLength1D(heap,arrayLength,2*arrayLength);
arrayLength*=2;
}
//寻找插入位置
//currentNode从新叶子向上移动
int currentNode=++heapSize;
while(currentNode!=1 && heap[currentNode/2]<theElement)
{
//不能插到heap[currentNode]
heap[currentNode]=heap[currentNode/2];//把元素向下移动
currentNode/=2;//currentNode移向双亲
}
heap[currentNode]=theElement;
}
大根堆的删除
在大根堆删除一个元素,就是删除根节点的元素。删除根节点后,将最后一个元素删除,并且变成新的根节点(使其还是完全二叉树)。此时二叉树需要重新排序。把此时的根节点和左右孩子元素大者进行交换,不停交换直到形成大根堆。时间复杂度为O(height)=O(logn)。
template<class T>
void maxHeap<T>::pop()
{
//删除最大元素
//如果堆为空,抛出异常
if(heapSize==0)
throw queueEmpty();
//删除最大元素
heap[1].~T();
//删除最后一个元素,重新建立堆
T lastElement=heap[heapSize--];
//从根开始,为最后一个元素寻找位置
int currentNode=1;
int child=2;
while(child<=heapSize)
{
//heap[child]应该是currentNode更大的孩子
if(child<heapSize && heap[child]<heap[child+1])
child++;
//可以放在heap[currentNode]吗
if(lastElement>=heap[child]
break;//可以
//不可以
heap[currentNode]=heap[child];//把孩子child向上移动
currentNode=child;//向下移动一层寻找位置
child*=2;
}
heap[currentNode]=lastElement;
}
大根堆的初始化
为了构建初始的非空堆,需要在空堆中执行n次插入操作。插入操作需要总时间为O(nlogn)。从最后一棵子树开始检查是否是大根堆,如果不是则调整,是则检查倒数第二棵,一直检查到根节点的树。
template<class T>
void maxHeap::initialize(T *theHeap,int theSize)
{
//在数组theHeap[1:theSize]中建大根堆
delete[] heap;
heap=theHeap;
heapSize=theSize;
//堆化,从最后一棵子树开始判断是否是最大堆,然后到倒数第二....
for(int root=heapSize/2;root>=1;root--)
{
T rootElement=heap[root];
//寻找位置
int child=2*root;
while(child<=heapSize)
{
//heap[child]应该是兄弟中较大者
if(child<heapSize && heap[child]<heap[child+1])
child++;
//可以把元素rootElement放在heap[currentNode]吗
if(rootElement>=heap[child])
break;//可以
//不可以
heap[child/2]=heap[child];//把最大孩子和根植交换
child*=2;
}
heap[child/2]=rootElement;
}
}