队列的定义
队列简称队,也是一种操作受限的线性表,其限制为仅允许在表的一端进行插入,在表的另一端进行删除操作,把进行插入的一端称为队尾(rear),向队列插入新元素称为进队或入队(enqueue),新元素进队之后成为新的队尾元素;从队列删除元素称为出队或离队(dequeue),元素出队后,其直接后继元素就成为新的队首元素。
由于队列元素进出的规则,队列又称为先进先出(FIFO)表。
需要注意的是,以上的规则仅对普通队列成立,双端队列两端都可以进行插入和删除。
队列的抽象数据类型描述
了解基本运算:
InitQueue(&q):初始化队列,构造一个空队列q
DestroyQueue(&q):销毁队列,释放队列q占用的存储空间
QueueEmpty(q):判断队列是否为空,若队列为空,则返回真,否则返回假
enQueue(&q,e):进队列,将元素e进队作为队尾元素
deQueue(&q,&e):出队列,从队列q中出队一个元素,并将其值赋给e
和栈一样,事实上还有很多的操作,不过里面比较基本的就是这几个操作。
队列的顺序存储结构
同样对于队列有两种模板,采用顺序存储结构的队列称为顺序队。
struct SqQueue{
ElemType data[MaxSize]; int front,rear;};//front和rear分别表示队头和队尾指针
基本运算的实现
顺序存储结构的都不难写。但在编写之前,希望大家每次搞不清front和rear到底指向什么时,就来看看下面的这张图:
front指向队首元素的前一个元素,rear指向队尾元素。
初始化队列
和栈一样,将两个指针设置为-1即可。
//初始化队列,将队头和队尾指针全部设置为-1即可
void InitQueue(SqQueue *&q){
q=(SqQueue *)malloc(sizeof(SqQueue)); q->front=q->rear=-1;}
销毁队列
顺序存储结构释放容器占用的空间都是一样的。
//销毁队列
void DestroyQueue(SqQueue *&q){
free(q);}
判断队列是否为空
队列为空时,队首的指针和队尾的指针的指向相同:
//判断队列是否为空
bool QueueEmpty(SqQueue *q){
return(q->front==q->rear);}
进队列
在队列不满时,先将队尾指针rear++,然后将元素e插入到该位置:
//进队列
bool enQueue(SqQueue *&q,ElemType e){
if (q->rear==MaxSize-1) return false;//队列q(伪)放满
q->rear++; q->data[q->rear]=e; return true;
}
为什么在这里添加一个伪字呢?因为q->rear==MaxSize-1时,队列中往往还存在很多空位置,这种因为队满条件设置不合理导致队满条件成立而队列中仍有空间的情况称为假溢出。后面会介绍另外一种大家熟悉地方式来解决这个问题。
出队列
需要判断一下队列是否为空。
//出队列,队列为空时队列中没有元素,出队失败
bool deQueue(SqQueue *&q,ElemType &e){
if (q->front==q->rear) return false;
q->front++; e=q->data[q->front]; return true;
}
基本运算合集如下:
struct SqQueue{
ElemType data[MaxSize]; int front,rear;};//front和rear分别表示队头和队尾指针
//初始化队列,将队头和队尾指针全部设置为-1即可
void InitQueue(SqQueue *&q){
q=(SqQueue *)malloc(sizeof(SqQueue)); q->front=q->rear=-1;}
//销毁队列
void DestroyQueue(SqQueue *&q){
free(q);}
//判断队列是否为空
bool QueueEmpty(SqQueue *q){
return(q->front==q->rear);}
//进队列
bool enQueue(SqQueue *&q,ElemType e){
if (q->rear==MaxSize-1) return false;//队列q(伪)放满
q->rear++; q->data[q->rear]=e; return true;
}//出队列,队列为空时队列中没有元素,出队失败
bool deQueue(SqQueue *&q,ElemType &e){
if (q->front==q-