循环队列——队列的表示和实现
---------队列的顺序存储结构---------
#define MAXSIZE;
typedef struct
{
QElemType *base; //存储空间的基地址
int front; //头指针
int rear; //尾指针
}SqQueue;
初始化时令front=rear=0,每当删除一个元素时,front值加一,每当插入一个元素时,rear值加一。因此在非空队列中,头指针始终指向队头元素,而尾指针始终指向队列尾元素的下一个位置
假设当前队列分配的最大空间为6,则当队列处于图d所示的状态时不可再继续插入新的队尾元素,否则会出现溢出现象,即因数组越界而导致的程序的非法操作错误。事实上,此时队列的实际可用空间并未占满,所以这种现象叫做“假溢出”。这是有“对尾入队,队头出队”这种受限制的操作造成的。
为了解决这个问题,引出了循环队列。将顺序队列换成一个环状的空间。
此时头尾指针以及队列元素之间的关系不变,只是在循环队列中,头尾指针“依环状增一”的操作可以“摸”运算来实现。通过取模,头指针和尾指针可以在顺序表空间里头尾衔接的方式进行循环移动。
对于循环队列不能用头尾指针是否相同来判断队列是否为空,因为当队满时也满足此条件。
解决办法如下:
①少用一个元素的存储空间(即队列空间大小为m时,有m-1个元素就认为是队满)
此时队空的条件是:Q.front=Q.rear;
队满的条件是:(Q.rear+1)%MAXSIZE=Q.front
②另设一个标志位判断队列是空还是满。
(1)循环队列初始化
Status InitQueue(SqQueue &Q)
{
Q.base=new QElemType[MAXSIZE];
if(!Q.base) return ERROR;
Q.front=Q.base=0;
return OK;
}
(2)求队列长度
int QueueLength(SqQueue &Q)
{
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE; //即返回队列之中的元素个数
}
(3)入队
Status EnQueue(SqQueue &Q,QElemType &e)
{
if((Q.rear+1)%MAXSIZE=Q.front) return ERROR;
Q.base[Q.rear]=e;
Q.rear=(Q.rear+1)%MAXSIZE; //队尾指针加1
return OK;
}
(4)出队
Status DeQueue(SqQueue &Q,QElemType &e)
{
if((Q.rear=Q.front) return ERROR;
e=Q.base[Q.front]; //保存队头元素
Q.front=(Q.front+1)%MAXSIZE; //队头指针加1
return OK;
}
(5)取队头元素
if((Q.rear=Q.front) return ERROR;
return Q.base[Q.front]; //返回队头元素的值,队头指针不变