引言:和栈相反,队列是一种先进先出(FIFO)的线性表,它只允许在表的一端进行插入,而在另一端删除元素,允许插入的一端叫做队尾(rear),允许删除的一端则称为队头(front),和线性表类似,队列也可以有两种存储表示
一、队列的链式表示和实现
用链表表示的队列简称链队列,一个链队列显然需要两个分别指示队头和队尾的指针才能唯一确定
1.队列的链式存储结构
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
typedef int QElemType;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
2.链队列的基本操作
Status InitQueue(LinkQueue &q) //构造一个空队列
{
q.front=q.rear=new QNode;
if(!q.front) exit(OVERFLOW);
q.front->next=NULL;
return OK;
}
Status DestroyQueue(LinkQueue &q) //销毁队列
{
while(q.front)
{
q.rear=q.front->next;
delete(q.front);
q.front=q.rear;
}
return OK;
}
Status ClearQueue(LinkQueue &q) //清空队列
{
while(q.front)
{
q.rear=q.front->next;
delete(q.front);
q.front=q.rear;
}
InitQueue(q);
return OK;
}
Status QueueEmpty(LinkQueue q) //判断队列是否为空
{
if(q.front==q.rear)
return OK;
else
return ERROR;
}
int QueueLength(LinkQueue &q) //求队列长度
{
int cnt=0;
while(q.rear)
{
q.rear=q.rear->next;
cnt++;
}
cout<<"队列长度为:"<<cnt;
return OK;
}
Status GetHead(LinkQueue q,QElemType &e) //用e返回队头元素
{
if(q.rear!=q.front)
{
e=q.front->next->data;
return OK;
}
else
return ERROR;
}
Status EnQueue(LinkQueue &q,QElemType e) //插入元素e
{
QNode *p=new QNode;
if(!p) exit(OVERFLOW);
p->data=e;
p->next=NULL;
q.rear->next=p;
q.rear=p;
return OK;
}
Status DeQueue(LinkQueue &q,QElemType &e) //删除队头元素并用e返回其值
{
QNode *p;
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;
}
二、队列的顺序表示和实现
和顺序栈相类似,在队列的顺序存储结构中,除了用一组地址连续的存储单元依次存放从队列头到队列尾,尚需附设两个指针 front 和 rear 分别指示队列头元素及队列尾元素的位置
1.循环队列的存储结构
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;
#define MAXQSIZE 100 //最大队列长度
typedef int QElemType;
typedef struct
{
QElemType *base; //初始化的动态分配存储空间
int front; //头指针,若队列不空,指向队列头元素
int rear; //尾指针,若队列不空,指向队列尾元素的下一个位置
}SqQueue;
2.循环队列的基本操作
Status InitQueue(SqQueue &q) //构造一个空队列
{
q.base=new QElemType[MAXQSIZE];
if(!q.base) exit(OVERFLOW);
q.front=q.rear=0;
return OK;
}
Status DestroyQueue(SqQueue &q) //销毁队列
{
delete(q.base);
return OK;
}
Status QueueEmpty(SqQueue q) //判断队列是否为空
{
if(q.rear-q.front==MAXQSIZE-1)
return OK;
else
return ERROR;
}
int QueueLength(SqQueue q) //求队列长度
{
return (q.rear-q.front+MAXQSIZE)%MAXQSIZE;
}
Status EnQueue(SqQueue &q,QElemType e) //插入元素e为新的队尾元素
{
if((q.rear+1)%MAXQSIZE==q.front) return ERROR;
q.base[q.rear]=e;
q.rear=(q.rear+1)%MAXQSIZE;
return OK;
}
Status DeQueue(SqQueue &q,QElemType &e) //删除队头元素,用e返回其值
{
if(q.front==q.rear) return ERROR;
e=q.base[q.front];
q.front=(q.front+1)%MAXQSIZE;
return OK;
}
三、C++标准模板类
1.deque类(双端队列)
deque模板类在deque头文件中声明(#include<deque>
),在STL中,其实现类似于vector容器,支持随机访问。主要区别在于,从deque对象的开始位置插入和删除元素的时间是固定的,而不像vector中那样是线性时间。所以如果多数操作发生在序列的起始和结尾处,则应考虑使用deque数据结构
2.queue模板类
queue模板类在头文件queue中声明(#include<queue>
),是一个适配器类
注意,pop() 是一个删除数据的方法,而不是检索数据的方法。如果要使用队列中的值,应首先使用front()来检索这个值,然后使用pop()将它从队列中删除