数据结构:队列及其应用
(一)什么是队列?
队列也是一种线性表,它只允许在表的一端进行插入操作,而在表的另一端进行删除操作。
- 队头(Front):只允许删除的一端,又称队首;
- 队尾(Rear):只允许插入的一端;
(二)队列的应用有哪些?
- 当我们需要顺序处理一组数据,但数据量在不断变化时可以使用队列来解题;
- 广泛应用于广度优先遍历中,比如当我们需要层次遍历二叉树的各个节点,就可以借助队列来实现。
(三)队列的存储结构有哪些?
(1)顺序存储
分配一块连续的存储单元存放队列中的元素
#define MaxSize 50 //定义队列中元素的最大个数
typedef struct{
ElemType data[MaxSize];//存放队列元素
int front,rear;//对头指针和队尾指针
}SqQueue
顺序存储有什么缺点?
不能用Q.rear== MaxSize 作为队满条件,因为当我们删除队列中的一个元素时会出现“假溢出”现象,即rear指针指向队尾,但data数组中依然存在可以存放元素的空位置。
(2)循环队列
① 什么是循环队列?
循环队列,即将顺序队列臆造出一个环形的空间,把存储队列元素的表从逻辑上视为一个环,称为循环队列。
循环队列可以解决“假溢出”问题。
循环队列中,当队首指针Q.front=MaxSize-1后,再前进一个位置就自动到队列下标为0的位置。(可以用取余运算来实现)
- 初始时:Q.front=Q.rear=0
- 队首指针进1:Q.front=(Q.front+1)%MaxSize
- 队尾指针进1:Q.rear=(Q.rear+1)%MaxSize
- 队列长度:(Q.rear+MaxSize-Q.front)%MaxSize
② 循环队列中队空队满的判断条件是什么?
方法一:牺牲一个存储单元
约定以“队头指针在队尾指针的下一位置作为队满的标志”
![[Pasted image 20221019192932.png|200]]
- 队满条件:(Q.rear+1)%MaxSize == Q.front
- 队空条件:Q.front == Q.rear
- 队列中元素的个数:(Q.rear-Q.front+MaxSize)%MaxSize
方法二:在队列类型中增设表示元素个数的数据成员
- 队满条件:Q.size == MaxSize
- 队空条件:Q.size == 0
- 队列中元素的个数:size
方法三:在队列类型中增设tag数据成员
约定删除元素设置tag=0、插入元素设置tag=1
- 队满条件:tag=1,插入导致Q.front == Q.rear
- 队空条件:tag=0,删除导致Q.front == Q.rear
④ 循环队列有哪些基本操作?
(1)初始化
void InitQueue(SqQueue &Q){
Q.rear=Q.front;
}
(2)判队空
bool isEmpty(SqQueue 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+!)%MaxSize;
return true;
}
(4)出队
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;
}