定义
队列(queue)是一种先进先出的线性表。它只允许在表的一端进行插入,在另一端进行删除,这如同我们日常生活中的排列是一致的,最早入队的元素最早离开。
队尾(rear)是队列中允许插入的一端,队头(front)是队列中允许删除的一端。
队列如同栈一样,也同样有两种存储表示,分别是顺序表示和链式表示。
循环队列—队列的顺序表示和实现
和顺序栈类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到对列尾的元素之外,需要设置两个指针front和rear分别指示队列头元素和尾元素的位置。
队列的顺序存储结构表示如下:
#define MAXQSIZE 100
typedef struct{
QElemType *base;
int front;
int rear;}SqQueue;
为方便C语言描述起见,约定:初始化建空队列时,front=rear=0,每当插入新元素至队尾时,“尾指针增一”,每当删除头元素时,“头指针增一”。因此,在非空队列中,头指针始终指向队列头元素,而尾指针始终指向队尾元素的下一个位置。
循环对列是将顺序队列变成一个环状的空间,用这种方法可以解决队列“假溢出”问题。
“假溢出”是指队列实际可用空间没有占满,但是不能向队列中添加新的队尾元素,否则会出现溢出的现象的情况。
在循环队列中,头尾指针以及队列元素之间的关系不发生改变,只是在循环队列中头尾指针“依次循环增一”的操作可用模运算实现。通过取模,头指针和尾指针就可以在顺序表空间内以头尾衔接的方式“循环”移动。
循环队列的基本操作算法描述:
Status InitQueue (SqQueue &Q)
{//构造一个空队列
Q.base=new QElemType[MAXQSIZE];
if(!Q.base) exit(OVERFLOW);
Q.front=Q.rear=0;
return ok;}
int QueueLength (SqQueue Q)
{//返回Q元素个数,即队列的长度
return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;}
Status EnQueue(SqQueue &Q,QElemType e)
{//插入元素e为Q的新的队尾元素
if((Q.rear+1)%MAXQSIZE==Q.front)
return ERROR;
Q.base[Q.rear]=e;
Q.rear=(Q.rear+1)%MAXQSIZE;
return ok;}
SElemType GetHead(SqQueue Q)
{//返回Q的队头元素,不修改队头指针
if (Q.front !=Q.rear)
return Q.base[Q.front];}
链队列—队列的链式表示和实现
链队是指采用链式存储结构实现的队列。通常链队用单链表来表示,一个链队显然需要两个分别指示对头和队尾的指针(分别称为头指针和尾指针)才能唯一确定。为了操作方便,同线性表的单链表一样,为链队添加头结点,并规定头指针始终指向头结点。
链队列存储结构表示如下:
typedef struct QNode
{QElemType data;
struct QNode *next;}QNode,*QueuePtr;
typedef struct
{QueuePtr front;
QueuePtr rear;}LinkQueue;
链队操作即为单链表插入和删除操作的特殊情况,只是需要进一步修改尾指针或头指针。
链队列的基本操作算法描述:
Status InitQueue (LinkQueue &Q)
{//构造一个空队列
Q.front=Q.rear=new QNode;
Q.front->next =NULL;
return ok;}
Status EnQueue(LinkQueue &Q, QElemType e)
{//插入元素e为Q的新的队尾元素
p=new QNode;
p->data=e;
p->next=NULL;
Q.rear->next=p;
Q.rear=p;
return ok; }
Status DeQueue(LinkQueue &Q,QElemType &e)
{//删除Q的队头元素,用e返回其值
if(Q.front==Q.rear) return ERROR;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear==p) Q.rear=Q.front;
delete p;
return ok; }
SElemType GetHead(LinkQueue Q)
{//返回Q的对头元素,不修改队头指针
if(Q.front != Q.rear)
return Q.front->next->data;}