队列
定义:是一种操作受限的线性表,只允许在表的一端进行插入,而在表的一端进行删除。
特性:先进先出(FIFO)
队头:允许删除的一端,又称队首。
队尾:允许插入的一端。
顺序存储
队列的顺序实现是指分配一块连续的存储单元存放队列中的元素,并设置两个指针:队头指针front指向队头元素,队尾指针rear指向队尾元素的下一个位置(可以有不同的定义)。
循环队列
将存储队列元素的表从逻辑上视为一个环,称为循环队列。
判空:Q.front==Q.rear
判满的三种处理方式:
1.牺牲一个单元来区分队空和队满,入队时少用一个队列单元
队满条件:(Q.rear+1)%MaxSize==Q.front
队列中元素个数:(Q.rear-Q.front+MaxSize)%MaxSize
2.类型中增设表示元素个数的数据成员。
队空:Q.size==0
队满:Q.size==MaxSize
3.类型中增设tag数据成员
队空:tag==0
队满:tag==1
链式存储
定义:同时带有队头指针和队尾指针的单链表。头指针指向队头结点,尾指针指向队尾结点,即单链表的最后一个结点。
判空:Q.front==NULL且Q.rear==NULL
出队:首先判断队列是否为空,不空,取出队头元素,将其从链表中摘除,并让Q.front指向下一个结点(若该结点为最后一个结点,则置Q.front==Q.rear==NULL)
入队:建立一个新结点,将新结点插入到链表的尾部,并改让Q.rear指向这个新插入的结点(若原队列为空,则令Q.front也指向该结点)
特点:适合数据元素变动比较大的情形,而且不存在队列满且产生溢出的问题。
双端队列
允许两端都可以进行入队和出队操作的队列
输入受限的双端队列:一端插入,两端删除
输出受限的双端队列:一端删除,两端插入
考点:判断输出序列的合法性。
应用
- 层次遍历二叉树
1. 根结点入队
2. 若队空,则结束遍历;否则,重复3操作
3. 队列中第一个结点出队,并访问之。若其有左孩子,则将左孩子入队,若其有右孩子,将右孩子入队。返回2操作。
- 页面替换算法
- 打印机问题
- CPU分配:程序结束或用完规定的时间间隔。
大题
- 若希望循环队列中的元素都能得到利用,则需设置一个标志域tag,并以tag的值为0或1来区分队头指针front和队尾指针rear相同时的队列状态是空还是满。编写入队和出队算法。
//思路:进队时置tag为1,出队时置tag为0(只有入队操作可能导致队满,只有出队操作可能导致队空)。队列初始时,置tag为0,front=rear=0
//队空:Q.front==Q.rear&&Q.tag==0
//队满:Q.front==Q.rear&&Q.tag==1
//入队
int EnQueue(SqQueue &Q,ElemType x){
if(Q.front==Q.raer&&Q.tag==1)
return 0;
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%MaxSize;
Q.tag=1;
return 1;
}
//出队
int DeQueue(SqQueue &Q, ElemType &x){
if(Q.front==Q.rear&&Q.tag==0)
return 0;
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
Q.tag=0;
return 1;
}
- Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法
void Inverser(Stack S,Queue Q){
while(!QueueEmpty(Q)){
x=DeQueue(Q);
Push(S,x);
}
while(!StackEmpty(S)){
Pop(S,x);
EnQueue(Q,x);
}
}
- 利用两个栈s1、s2来模拟一个队列
Push(S,x)元素x入栈S
Pop(S,x)S出栈并赋值给x
StackEmpty(S)判断栈是否为空
StackOverflow(S)判断栈是否为满
如何利用栈的运算实现该队列的3个运算
Enqueue将元素x入队
Dequeue出队,并将出队元素存储在x中
QueueEmpty判断队列是否为空
//对s2的出栈操作 用作出队,若s2为空,则先将s1中的所有元素送入s2
//对s1的入栈操作 用作入队,若s1满,必须先保证s2为空,才能将s1中的元素全部插入s2中
//入队
int EnQueue(Stack &s1,Stack &s2,ElemType e){
if(!StackOverflow(s1)){
Push(s1,e);
return 1;
}
if(StackOverflow(s1)&&!StackEmpty(s2)){
printf("队列满");
return 0;
}
if(StackOverflow(s1)&&StackEmpty(s2)){
while(!StackEmpty(s1)){
Pop(s1,x);
Push(s2,x);
}
Push(s1,e);
return 1;
}
}
//出队
void DeQueue(Stack &s1,Stack &s2, ElemType &x){
if(!StackEmpty(s2))
Pop(s2,x);
else if(StackEmpty(s1))
printf("队列为空");
else{
while(!StackEmpty(s1)){
Pop(s1,x);
Push(s2,x);
}
Pop(s2,x);
}
}
//判空
int QueueEmpty(Stack s1,Stack s2){
if(StackEmpty(s1)&&StackEmpty(s2))
return 1;
else
return 0;
}