队列
注:本节开始,我会在开头对本节内容的基础内容进行一个归纳,然后才是习题。
队列基础知识:
队列也是一种操作受限的线性表,其特征是先进先出,只能在队首出,队尾进,类似于排队。
不同存储方式的队列
1),顺序存储
#define Maxsize 50 typedef struct queue{ elemtype data[Maxsize]; int front , rear; }SQqueue;普通的顺序存储存在的问题是当前面入队的数据弹出后,front后移,而front之前的空间就浪费了,有空的空间,但是确无法再入队。
此时针对这个问题,对顺序存储进行一定的调整,使之变为环形,于是就有了循环队列
循环队列:
对front 和rear 进行对队长取余就可以实现,这样当队列空时,front = rear ,队满时可以用不同的方法确定。
大部分情况下都是约定rear + 1 == front 的情况为满队。
2),队列的链式存储结构
typedef struct Linknode{ int data; struct Linknode *Next; }Linknode; typedef struct{ Linknode *front , *rear; }*Linkqueue;front 指针指向头结点,rear指向尾结点,入队就用尾插法,出队就是删除第一个结点,每次入队都要更新rear。
3),双端队列
队列可以从两边进行插入和删除
输入受限的双端队列:输入只能从一端输入,输出可以从两边输出
输出受限的双端队列:输出只能从一端输出,输入可以从两边输入
一,选择题
1,栈和队列的主要区别是:
插入和删除的操作的限定不一样
2,循环队列存储在数组A[0…n]中,入队时的操作是
rear = (rear + 1) % (n+1);
注:取余不是n是因为,当n为n-1时插入元素则会直接跳转到0,而不会到n,所以是取余n+1而不是n;
3,用链式存储方式的队列进行删除操作时需要:头尾指针都有可能要修改
∵链式队列里,插入是使用的尾插法,所以要删除元素时,是删除链表的第一个元素,但是当队列里只有一个元素的时候,删除元素就需要修改队首指针也需要修改队尾指针。
4,若以1,2,3,4作为双端队列的输入序列,则既不能用输出受限的双端队列输出,也不能用输入受限的双端队列输出的输出序列是:4,2,3,1
对于输出受限的双端队列,入队顺序是1,2,3,4所以3没办法插在1,2中间
对于输入受限的双端队列,2没法比3和1先输出,因为2肯定在1,3中间
5,已知循环队列存储在一维数组A[0…n-1]中,切队列非空时要求front指向队头元素而rear指向队尾元素,初始队列为空,要求现在输入一个数据,使得存放在A[0],则初始时front和rear分别为多少。
因为初始为空插入后front依然是队首,所以front不用改变依然是0,所以front原来就是0,因为在插入一个元素后,rear要进行+1然后mod n,如果开始为0,则第一个元素进来后会变成1,而初始为n-1时,就是A[0]所以front和rear分别为0,n-1;
二,综合应用题
1,写出一个用tag为0|1表示队列空与否的循环队列的入队和出队操作。
队列的结构和初始化
struct SQqueue{
int data[Maxsize];
int front , rear ,tag;
}SQqueue;
void init_queue(SQqueue q)
{
q.front = q.rear = 0;
tag = 0;//tag == 0 表示此时队空
}
入队操作
bool push(SQqueue q , int x)
{
if(q.front == q.rear && q.tag == 1)return false;//判断是否满队
q.data[q.rear] = x;
q.rear = (q.rear++)%Maxsize;
if(q.rear == q.front)tag = 1;
return true;
}
出队操作
bool front(SQqueue q , int &x)
{
if(q.front == q.rear && q.tag == 0)return false;//判断是否队空
x = q.data[q.front];
q.front = (q.front++)%Maxsize;
if(q.front == q.rear) tag =0;
return true;
}
2,Q是一个队列,S是一个栈,实现将队列中的元素逆置。
思路:弹出然后入栈,全部入栈了再重新入队,太简单了难得写没意义
3,用两个栈来模拟一个队列
push(s,x) //元素x入栈s
pop(s,x) //出栈将栈顶元素给x
stackempty(s) //判断栈是否为空
stackoverflow(s) //判断是否栈满
用以上的操作模拟队列一下操作
enqueue //元素x入队
dequeue //元素出队
queueempty //判断是否为空队列
思路:将入队的序列用逆序存入栈内就可以使出栈顺序变成出队的顺序。所以我们用s2来逆序入队元素,用s1当队列的存储的位置。
void enqueue(int x)
{
if(stackoverflow(s1))
{
//如果满了就不能入队
return false;
}
int m;
while(!stackempty(s1))//先将原来的压入s2,然后再将全部压回s1.
{
pop(s1,m);
push(s2,m);
}
push(s2,x);
while(!stackempty(s2))
{
pop(s2,m);
push(s1,m);
}
}
void dequeue(int &x)
{
pop(s1,x); //出队直接s1出栈就行。
}
bool queueempty()
{
if(stackempty(s1))//s1不为空队列就不为空。
{
return true;
}
return false;
}
第四题就不写了,不想写了。。。
本文详细介绍了队列的基本概念,包括顺序存储的局限、循环队列的实现、链式存储的队列以及双端队列的特点。还通过选择题和综合应用题的形式探讨了队列的入队和出队操作,以及如何用栈模拟队列和逆序队列的操作。
973

被折叠的 条评论
为什么被折叠?



