队列的一个非常重要的特点就是:只允许在队列的头部进行删除操作,只允许在队列的尾部进行插入操作。

所以,很明显,队列这种结构需要两个指针,一个指针指向队列的头部,一个指针指向队列的尾部。既然队列这种结构也是用来存放数据的,当有一个数据存入队列中时,指向尾部的指针就向后加1,当删除一个元素时,头指针就向后加1,由于我们定义当队列为空时,指向头部的指针和指向尾部的指针重合,所以,当删除到剩余最后一个元素时,头指针front和尾指针rear就重合了,这样会和我们定义的队列为空两指针重合相矛盾。所以,我们要做的就是,将尾指针rear指向队列尾部的下一个位置。这样,问题就解决了。

如果有数据插入,我们可以将rear+1,当数据不需要而要将其删除时,我们将front+1,直到rear指向队列尾部的下一个位置,已经没有位置可以放新的元素了,那么此时队列真的已经满了吗?当然没有,因为删除一个元素时,front++,所以,在front前面还有位置可以放元素,所以此时,这种虚假的队列满的情况,称之为“假溢出”。

那么如何解决这个假溢出的现象呢?当然有办法,就是通过循环队列,当rear指针指向最后一个位置时,就将它置为0,指向队列头部。那假设我们有了一个循环队列,当rear向后自增,又从0开始接着向后自增,直到和front重合时,队列满。这样一来,我们又带来一个问题,我们怎么判断rear==front到底是队列为空还是队列是满的呢?解决的办法就是空出一个单元,不存放任何数据,也就是当rear+1 == front时,就意味着满队列了。所以,判断满队列的条件就是:

(reat+1)%QueueSize==front;

此时,就认为是满队列状态。

那么我该如何计算队列的长度呢?因为rear有可能比front大也有可能比front小,我该如何确定队列的元素个数呢?第一种情况,rear > front。此时,只要将rear - front就可以计算出队列的长度了。

由图所示,图中有2个元素,a3和a4。所以,我们要计算队列长度,只需将rear-front,就可以得出结果了。第二种情况,rear < front。如图所示:

当碰到这种出现假溢出形式的时候,我们该如何计算队列的长度呢?很明显,此时,队列长度的计算分为两段,一段是front之后的元素,一段是rear之前的元素,计算A3和A4这两个元素,我们只需(QueueSize - front)这样以来,就算出来了,此时QueueSize的值为5,那么(5 - 3 )的值为2,所以,第一段元素的长度为2,第二段元素长度,只需要(0 + rear ) 就可以了,也就是(0 + 2 ),此时值为2,所以,队列真正的长度就为(2 + 2 = 4 ), 那么队列的长度就计算出来了。

因为有两种情况,所以,为了实现通用,就有一个标准的计算队列长度的公式:

(rear-front+QueueSize)%QueueSize

接下来,就来定义一个循环队列的结构:

typedefintQElemType;typedefstruct{QElemTypedata[MAXSIZE];intfront;intrear;}SqQueue;

如果要初始化一个队列,我们该如何做呢?

StatusInitQueue(SqQueue*Q){Q->front=0;Q->rear=0;returnOK;}

求循环队列的长度

intQueueLength(SqQueueQ){return(Q.rear-Q.front+MAXSIZE)%MAXSIZE;}

循环队列元素的插入

StatusEnQueue(SqQueue*Q,QElemTypee){if((Q->rear+1)%MAXSIZE==front)returnERROR;Q->data[Q->rear]=e;Q->rear=(Q->rear+1)%MAXSIZE;returnOK;}

循环队列元素的删除

StatusDeQueue(SqQueue*Q,QElemType*e){if(Q->rear==Q->front)returnERROR;*e=Q->data[Q->front];Q->front=(Q->front+1)%MAXSIZE;returnOK;}