极大队列基本操作实现
-
概念
优先队列
是按照某种优先级进行排列的队列,优先级越高的元素出队越早,优先级相同按照先进先出的原则进行处理。
采用堆
来实现优先队列,入队和出队的时间复杂度均为对数级别
堆
是具有下列性质的完全二叉树:每个结点的值都小于或等于其左右孩子结点的值(成为小根堆);或者每个结点的值都大于或等于其左右孩子结点的值(成为大根堆)。 -
定义PriQueue类
template <class T>
class PriQueue
{
public:
PriQueue();//构造函数 初始化空极大队列
~PriQueue();//析构函数
void EnQueue(T x);//入队操作 将元素x入队
T DeQueue();//出队操作 将队头元素出队
T GetHead();//取队头元素(并不删除)
bool Empty();//判断队列是否为空
private:
T data[QueueSize];//存放队列元素的数组
int rear;//游标 队尾指针
};
- 入队操作的实现
template <class T>
void PriQueue<T>::EnQueue(T x)
{
int i;
T temp;
if (rear + 1 == QueueSize)
{
throw "上溢";
}
i = rear++;
data[i] = x;
while (i / 2 > 0 && x > data[i / 2])
{
temp = data[i];
data[i] = data[i / 2];
data[i / 2] = temp;
i = i / 2;
}
}
优先队列的入队操作先将待插元素x插入队尾位置,然后将新插入元素从叶子向根方向进行调整,若新插入元素比双亲大,则进行交换,这个过程一直进行到根结点或新插入元素小于其双亲结点的值
- 出队操作的实现
template <class T>
T PriQueue<T>::DeQueue()
{
int i = 1, j = 2 * i;
T temp;
if (rear == 0)
{
throw "下溢";
}
T x = data[1];
data[1] = data[rear--];//没有rear--
while (j <= rear)
{
if (j < rear && data[j] < data[j + 1])//漏了j<rear,当j=rear时j不能再自加,否则数组会越界
{
j++;
}
if (data[i] > data[j])
{
break;
}
else
{
temp = data[i];
data[i] = data[j];
data[j] = temp;
}
i = j;
j = 2 * i;
}
return x;
}
由于优先队列的队头元素位于堆顶,因此出队操作直接输出栈顶元素,为维护堆的性质,将队尾元素放到根结点,然后调整根结点重新建堆。