循环队列头指针为front,队列尾指针为rear,队列容量为M,则元素个数为(rear-front+M)%M
循环队列满时,数组中还有一个空的单元。如图4-12-8所示,我们认为,队列已经满了,也就是说,我们不允许出现4-12-7的右图情况出现。
队列满的条件是:
(rear+1)%QueueSize == front
通用的计算队列长度的公式为:
(rear - front+ QueueSize)%QueueSize
为了解决顺序队列中的"假溢出"问题,需要把数组想象为一个首尾相接的环,称这种数组为"循环数组",存储在其中的队列成为"循环队列"。
解决队满、队空的判断问题有3种方法:
①设置一个布尔变量以区别队满还是队空。
②浪费一个元素的空间,用于区别队满还是队空。
③是用一个计数器记录队列中的元素个数(即队列长度)。
在使用中,大都采用第②种方法,即队头、队尾指针中有一个指向元素,而另一个指向空闲元素。
通常约定队尾指针指示队尾元素在一维数组中的当前位置,队头指针指示在一维数组中的当前位置的前一个位置。这种顺序队说明如下:
①队头指针的引用为q->front,队尾指针的引用为q->rear。(q 为队列名)
②初始时,设置q->front=q->rear=0。
③入队操作:在队列未满时,队尾指针先加1(要取模),再送值到队尾指针指向的空闲元素。
④出队操作:在队列非空时,队头指针先加1(要取模),再从队头指针指向的队头元素处取值。
⑤队空的条件:q->front=q->rear;队满的条件:q->front=(q->rear+1)% QueueSize。
⑥队列长度为(q->rear+QueueSiz-q->front)% QueueSize。
在循环队列的操作时应注意,队头指针、队尾指针加1时,都要取模,以保持其值不出界。
在循环队列上实现的基本运算:
①初始化InitQueue(q)。
void InitQueue(qnode*&q){q=(qnode*)malloc(sizeof(snode)); ∥指针初始化
q->rear=q->front=0;
}
②判定队列是否为空Emptyq(q)。
int Emptyq(snode*q){if(q->rear=q->front)
return 1;
else return 0;
}
③入队列EnQueue(q,x)。
int EnQueue(qnode*q,ElemType x)
{if((q->rear+1)%QueueSize==q->front) ∥队满
return 0;
q->rear=(q->rear+1)%QueueSize; ∥队尾指针进1
q->data[q->rear]=x;
return 1;
} }
④出队列OutQueue(qnode*q,ElemType x)。
int OutQueue(qnode*q,ElemType x)
{if(q->rear=q->front)
return 0;
q->front=(q->front+1)%QueueSize; ∥队头指针进1
x=q->data[q->front];
return 1; } }
⑤取队头元素GetHead(q,x)。
int GetHead(qnode*q,ElemType &x)
{if(q->rear=q->front)
return 0;
x=q->data[(q->front+1)%QueueSize];
return 1; } }
双端队列
双端队列(DeQue)是限定插入删除操作在表的两端进行的线性表。这两端分别叫做端点1和端点2。在实际使用中,可以有输出受限的双端队列,即一个端点允许插入和删除,另一个端点只允许插入的双端队列和输入受限的双端队列,即一个端点允许插入和删除,另一个端点只允许删除的双端队列。而如果限定双端队列从某个端点插入的元素只能从该端点删除,则该双端队列就蜕变为两个栈底相邻接的栈了。