写在最前
一、队列的基本概念
- 队列:队列,简称队,也是一种受限的线性表,只允许在表的一端尽心插入,而在表的另一端进行删除。
- 队头:允许删除的一端,也称队首。
- 队尾:允许插入的一端。
- 空队列:不含任何元素的空表。
- FIFO:先进先出。
二、队列常见的基本操作
- InitQueue(&Q):初始化队列,构造一个空队列Q。
- QueueEmpty(Q):判队列空,若队列Q空,返回true,否则返回false。
- EnQueue(&Q,x):入队,若队列Q未满,将加入,使之成为新的队尾。
- DeQueue(&Q,&x):出队,若队列Q非空,删除队头元素,并用x返回。
- GetHead(Q,&x):读队头元素,若队列Q非空,则将队头元素赋值给x。
注 意 : \color{red}注意: 注意:
栈和队列是操作受限的线性表,对线性表的操作不是都可以作栈和队列的操作,比如,不可以随便读取栈或队列中间的某个数据。
三、队列的顺序存储
3.1顺序队列
队列的顺序实现是指分配一块连续的存储的单元来存放队列中的元素,并用front指针指向队头元素,rear指针指向队尾元素的下一个。
//队列的定义
#define MaxSize 50
typedef struct
{
ElemType data[MaxSize]; //静态数组存放队列元素
int front,rear; //队头和队尾指针
} SqQueue;
对于上图来说:
初始状态(队空条件):Q.front == Q.rear(==0)。
进队操作:队不满时,先送值到队尾元素,再将队尾指针+1。
出队操作:队不空时,先取队头元素值,再将队头指针-1。
此时对于图(d),即使满足队空条件。再进行入队操作就会出现“上溢出”现象,但此时队列仍有空位置,所以这是一种”假溢出”。
3.2循环队列
针对顺序队列的缺点,我们引出循环队列,即把存储队列元素的表从逻辑上视为一个环。利用除法取余运算实现。
//初始化
void InitQueue(SqQueue &Q)
{
Q.rear=Q.front=0;
}
//判队空
bool QueueEmpty(Queue Q)
{
if(Q.rear==Q.front)
}
//读队头
bool GetHead(SqQueue Q,ElemType &x)
{
if(Q.rear==Q.front)
return false;
x=Q.data[Q.rear];
return true;
}
//入队
bool EnQueue(SqQueue &Q,ElemType x)
{
if((Q.rear+1)%MaxSize==Q.front)
return false;
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%MaxSize;
return true;
}
//出队
bool DeQueue(SqQueue &Q,ElemType &x)
{
if(Q.rear=Q.front)
return false;
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
return true;
}
区 分 队 空 还 是 队 满 : \color{red}区分队空还是队满: 区分队空还是队满:
1.普遍做法为牺牲一个单元
队满:(Q.rear+1)%MaxSize==Q.front
队空:Q.front == Q.rear
队列中元素的个数:(Q.rear-Q.front+MaxSize)%MaxSize
2.队列中定义一个变量size表示元素个数
队空,Q.size=0;队满,Q.size=MaxSize(这种情况下有Q.front==Q.rear,但该条件不是队空条件)
3.增设tag数据成员,tag=0时,若因删除导致Q.front == Q.rear,则为队空;tag=1时,若因插入导致Q.front==Q.rear,则为队满。
Q.front ==Q.rear&&tag ==1 队满
Q.front ==Q.rear&&tag ==0 队空
四、队列的链式存储结构
队列的链式表示称为链队列,实际上是一个同时带有队头指针和队尾指针的单链表。头指针指向队头结点,尾指针指向队尾结点(与顺序存储不同),即单链表的最后一个结点。
//带头结点
//链式定义
typedef struct
{
ElemType data;
struct LinkNode *next;
} LinkNode;
typedef struct
{
LinkNode *front,*rear;
} LinkQueue;
//初始化
void InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=(LinkQueue *)malloc(sizeof(LinkNode));
Q.front->next=NULL;
}
//判队空
bool QueueEmpty(LinkQueue Q)
{
if(Q.front==Q.rear)
return true;
else
return false;
}
//入队
bool EnQueue(LinkQueue &Q,ElemType x)
{
LinkNode *s=(LinkNode *)malloc(sizeof(LinkNode));
s->data=x;
s->next=NULL; //创建新结点,插入到链表尾
Q.rear->next=s;
Q.rear=s;
}
//出队
bool DeQueue(LinkQueue &Q,ElemType &x)
{
if(Q.rear==Q.front)
return false;
LinkNode *p=Q.front->next;
x=p->data;
Q.front->next=p->next;
if(Q.rear==p) //若原队列只有一个结点,删除后变空
Q.rear=Q.front;
free(p);
return true;
}
五、双端队列
双端队列:两端都可以进行入队和出队操作的队列,逻辑结构也为线性的
输出受限的双端队列:
输入受限的双端队列: