![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/47618871a67326d4f2675dee1e2bbc11.png)
为了解决假溢出现象并使得队列空间得到充分利用,一个较巧妙的办法是将顺序队列的数组看成一个环状的空间,即规定最后一个单元的后继为第一个单元,我们形象地称之为循环队列。
- 假设队列数组为 Queue[MAXSIZE],当 rear+1=MAXSIZE 时,令 rear=0,即可求得最后一个单元 Queue[MAXSIZE-1]的后继:Queue[0]。
- 更简便的办法是通过数学中的取模(求余)运算来实现:rear=(rear+1)mod MAXSIZE,显然,当 rear+1=MAXSIZE 时,rear=0, 同样可求得最后一个单元 Queue[MAXSIZE-1]的后继:Queue[0]。
- 所以,借助于取模(求余) 运算,可以自动实现队尾指针、队头指针的循环变化。
进队操作时,队尾指针的变化是:rear= (rear+1)mod MAXSIZE ;
而出队操作时,队头指针的变化是:front=(front+1)mod MAXSIZE。 下图给出了循环队列的几种情况。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/8644ef73d66e9c0b532e03968a64421f.png)
与一般的非空顺序队列相同,在非空循环队列中,队头指针始终指向当前的队头元素,而队尾指针始终指向真正队尾元素后面的单元。
在下图 ©所示 循环队列中,队列头元素 是 e3,队列尾元素是 e5,当 e6、e7和 e8相继入队后,队列空间均被占满,如上图 (b)所示, 此时队尾指针追上队头指针,所以有:front =rear。
反之,若 e3、e4 和 e5相继从上图 ©的 队列中删除,则得到空队列,如上图 (a)所示,此时队头指针追上队尾指针,所以也存在关 系式:front = rear。
可见,只凭 front = rear 无法判别队列的状态是“空”还是“满”。
- 对于这个问题,可有两种处理方法:一种方法是少用一个元素空间。当队尾指针所指向的空单元 的后继单元是队头元素所在的单元时,则停止入队。这样一来,队尾指针永远追不上队头指针,所以队满时不会有 front =rear。
- 判队“满”的条件为(rear+1)mod MAXSIZE=front
- 判队空的条件,仍为 rear=front
另一种是增设一个标志量 tag的方法,以区别队列是“空” 还是“满”。初始化操作即产生一个空的循环队列,此时 Q->front = Q->rear=0,tag=0;当空的循环队列中有第一个元素入队时,则 tag=1,表示循环队列非空;当 tag=1 且 Q->front=Q->rear 时,表示队满。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/86fa6b12c566bb2c71b906c86a340768.png)
#define MAXSIZE 50
typedef struct
{
QueueElementType element[MAXSIZE];
int front;
int rear;
} SeqQueue;
void InitQueue(SeqQueue *Q)
{
Q->front = Q->rear = 0;
}
int EnterQueue(SeqQueue *Q, QueueElementType x)
{
if ((Q->rear + 1) % MAXSIZE == Q->front)
return (FALSE);
Q->element[Q->rear] = x;
Q->rear = (Q->rear + 1) % MAXSIZE;
return (TRUE);
}
int DeleteQueue(SeqQueue *Q, QueueElementType *x)
{
if(Q->front == Q->rear)
return (FALSE);
*x = Q->element[Q->front];
Q->front = (Q->front + 1) % MAXSIZE;
return (TRUE);
}