3.2.1队列的基本概念
1,队列的定义
队列:是一种操作受限的线性表,只允许在表的一端进行插入,而在表的另一端进行删除。
向队列中插入元素成为入队或进队;删除元素称为出队或离队。
特性:先进先出 又称先进先出的线性表
2,队列常见的基本操作
InitQueue(&Q):初始化队列,构造空队列Q
QueueEmpty(Q):判断队列是否空,若队列Q为空返回true,否则返回false
EnQueue(&Q,&x):入队,若队列Q未满,将x加入,使之成为新的队尾。
3.2.2队列的顺序存储结构
1,队列的顺序存储
队列的顺序实现是指分配一块连续的存储单元存放队列中的元素,并附设两个指针front 和 rear 分别指示队头和队尾的位置。
设队头指针指向队头元素,队尾指针指向队尾元素的下一个位置
队列的顺序存储类型可描述为
#define Maxsize 50
typedef struct {
ElemType data[Maxsize];
int front,rear;
}Squeue
2,循环队列
为了区分队空还是队满,有三种处理方式:
1)牺牲一个单元来区分队空和队满,入队时少用一个队列单元,这是较为普遍的做法。
2)类型中增设表示元素个数的数据成员。这样,则队空的条件为Q.size==0;队满的条件为Q.size == Maxsize。这两种情况都有Q.front == Q.rear
3)类型中增设tag成员,以区分是队满还是队空。tag==0情况下,若因删除导致Q.front == Q.rear 则为队空;tag==1情况下,若因插入导致Q.front == Q.rear则为队满。
3,循环队列的操作
1)初始化
voild InitQueue(&Q){
Q.rear = Q.front=0; //初始化队首,队尾指针
}
2)判队空
bool isEmpty(Q){
if(Q.rear == Q.front ){
return true;
}else{
return false;
}
}
3)入队
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; // 队尾指针增加1 取模
return true;
}
4)出队
bool DeQueue(SqQueue &Q,ElemType &x){
if((Q.rear+1)%MaxSize == Q.front){
return false; //队满
}
x=Q.data[Q.front];
Q.front =(Q.front + 1)%MaxSize; //队头指针加1 取模
return true;
}
3.2.3队列的链式存储结构
1,队列的链式存储
队列的链式表示称为链队列,它实际上是一个同时带有头指针和队尾指针的单链表。头指针指向队头结点,尾指针指向队尾结点,即单链表的最后一个结点。
当Q.front == null 并且 Q.rear ==null 时,链式队列为空。
出队时,首先判断队是否为空,若不为空,则取出队头元素,将其从链表中摘除,并让Q.front指向下一个结点(若该结点为最后一个结点,则置Q.front 和 Q.rear 都为 null)。
入队时,建立一个新结点,将新结点插入到链表的尾部,并且让Q.rear指向这个新插入的结点(若原队列为空队,则令Q.front也指向该结点)。
通常将链式队列设计成一个带头结点的单链表,这样插入和删除操作就统一了。
2,链式队列基本操作
3.2.4双端队列
双端队列是指允许两端都可以进行入队出队操作的队列。元素的逻辑结构是线性结构。
将队列两端分别称前端和后端,两端都可以入队和出队。
在双端队列进队时:前端进的元素排列在队列中后端进的元素前面,后端进的元素排列在队列中前端进的元素的后面。
在双端队列出队时:无论前端还是后端出队,先出的元素排列在后出的元素的前面。