第三章
栈和队列
一. 基本要求、重点、难点
本章的目的是介绍栈和队列的逻辑结构定义及在两种存储结构上如何实现栈和队列的基本运算。要求在掌握栈和队列的特点的基础上,懂得在什么样的情况下能够使用栈或队列。本章重点是掌握栈和队列在两种存储结构上实现的基本运算,难点是循环队列中对边界条件的处理。
二. 考核目标和考核要求
要求达到识记层次的有:栈和队列的特点,什么样的情况下能够使用栈或队列
要达到综合应用层次的有:栈的逻辑结构特点,栈与线性表的异同;顺序栈和链栈上实现的进栈、退栈等基本算法;栈的“上溢”和“下溢”的概念及其判别条件;利用栈设计算法解决简单的应用问题;队列的逻辑结构特点,队列与线性表的异同;顺序队列(主要是循环队列)和链队列上实现的入队、出队等基本算法;队列的“上溢”和“下溢”的概念及其判别条件;使用数组实现的循环队列取代普通的顺序队列的原因;循环队列中对边界条件的处理方法;利用队列设计算法解决简单的应用问题。
三.
练习题
1. 单项选择题
1.1栈是一种受限的线性表,它的特点是( B
)
A)
先进先出
B)
后进先出
C)
进优于出
D)
随机进出
1.2设一个栈的输入序列为a,b,c,d,则所得出栈的输出序列不可能是( D
)
A)
a,b,c,d
B)
d,a,b,c
C)
a,c,d,b
D)
d,c,b,a
1.3由两个栈共享受1个向量空间的好处是( D
)
A)
减少存取时间,降低下溢发生的几率
B)
节省存储空间,降低下溢发生的几率
C)
减少存取时间,降低上溢发生的几率
D)
节省存储空间,降低上溢发生的几率
1.4设有一个空栈,现有输入序列为1,2,3,4,5,经过pusu,push,pop,push,pop,pop,push,push,pop后输出序列是( C )
A)2,3,4,5
B)5,1,3,4
C)2,3,1,5
D)3,1,4,2
1.5判断一个顺序表st(最多元素为StackSize)为栈满的条件是( D
)
A)
st.top!= StackSize
B)
st.top!=0
C)
st.top==-1
D)
st.top==StackSize-1
1.6一个队列的入队序列是1,3,5,7,9,则出队的输出序列只能是(
B )
A)9,7,5,3,1
B)1,3,5,7,9
C)1,5,9,3,7
D)9,5,1,7,3
1.7判断一个顺序队列sq(最多元素为QueueSize)为空队列的条件是( A
)
A)
sq.rear==cq.front
B)
sq.rear==0
C)
sq.front==QueueSize
D)
sq.rear==QueueSize+1
1.8判断一个循环队列cq(最多元素为QueueSize)为满队列的条件是( C
)
A)
cq.rear==cq.front
B)
cq.rear==QueueSize
C)
(cq.rear+1)% QueueSize==cq.front
D)
cq.rear%QueueSize+1==cq.front
1.9队列中的元素个数是( B
)
A)
不变的
B)
可变的
C)
任意的
D)
0
1.10同一队列内各元素的类型( A
)
A)
必须一致
B)
可以不一致
C)
不能一致
D)
不限制
1.11循环队列占用的空间( A
)
A)
必须连续
B)
可以不连续
C)
不能连续
D)
不必连续
1.12容量是10的循环队的头指针的位置Sq.front为2,则队的头元素的位置是( B
)
A)
2
B)
3
C)
1
D)
0
1.13初始化一个空间大小为5的顺序栈Ss后,Ss->top的值( A
)
A)
是-1
B)
不定
C)
不再改变
D)
动态变化
1.14经过下列栈的运算后StackTop(s)的值是(
A )
InitStack(s);Push(s,a);Push(s,b),Pop(s);
A)
a
B)
b
C)
1
D)
2
1.15经过下列栈的运算后*x的值是(
B )InitStack(s);Push(s,a);Push(s,b),StackTop(s);
Pop(s,x);
A)
a
B)
b
C)
1
D)
2
1.16一个循环队列一旦说明,其占用空间的大小( A
)
A)
已固定
B)
可以改变
C)
不能固定
D)
动态变化
1.17队列结构属于下列结构中的( B
)
A)
集合
B)
线性
C)
树型
D)
网状
1.18设数组data[m]作为循环队列SQ的存储空间,front为队头指针,rear为队尾指针,则执行出队操作后其头指针front的值为( D
)
A)
front=front+1
B)
front=(front+1)%(m-1)
C)
front=(front-1)%m
D)
front=(front+1)%m
1.19存放循环队列元素的数组data有10元素,则data数组的下标范围是( B
)
A) 0……10
B) 0……9
C) 1……10
D) 1……9
1.20存放循环队列Sq元素的数组data有10个元素,Sq->front为9,队列的头元素的位置在( A )
A) 9
B) 0
C) 1
D) 10
2. 填空题
2.1栈又称后进先出表,队列又称为[先进先出]表
2.2设S[maxsize]为一个顺序存储的栈,变量Top指向栈顶位置,栈为空的条件是[S.top==-1]
2.3设S[maxsize]为一个顺序存储的栈,变量Top指向栈顶位置,栈为满的条件是[S.top==masize-1]
2.4对栈进行入栈操作时,应先判别栈是否为[栈满]
2.5对栈进行退栈操作时,应先判别栈是否为[空栈]
2.6已知一个栈的输入序列为1,2,3,…,n,则其输出序列的第2个元素为n的输出序列的个数是[n-1]
2.7设sq[maxsize]为一个顺序存储的栈,变量top(为负数时栈为空)指示栈顶元素的位置,能做入栈操作的条件是[S.top<maxsize-1]
2.8设sq[maxsize]为一个顺序存储的栈,变量top(为负数时栈为空)指示栈顶元素的位置,如要把栈顶元素弹出并送到x中,则需执行下列语句:[x=s.data[s.top];s.top=s.top+1;]
2.9元素进入队列的那端是[队尾]
2.10对链栈ls,指向栈顶元素的指针是[ls->next]
2.11链栈ls是空栈的条件是[ls->next==NULL]
2.12链栈ls的栈顶元素是链表的[首]元素
2.13栈s经过运算InitStack(s);Push(s,a);Push(s,b)后StackTop(S)的值是[b]
2.14已知循环队列sq,在进行出队操作之前首先要判断[队空否]
2.15循环队列sq存储在数组sq.data[0…max]中,sq.front为i,则存放队列头元素的数组元素是[sq.data[i]]
2.16循环队列sq存储在数组sq.data[0…max]中,sq.rear为0,则存放队列尾元素的数组元素是[sq.data[max]]
2.17循环队列sq存储在数组sq.data[0…max]中,则sq中最多能存放[max+1]个队列元素
2.18在链队列lq中,链队的尾元素是链表的[尾]元素
2.19循环队列sq经过运算InitQueue(sq),
sq.front=[0]
2.20循环队列sq经过运算InitQueue(sq),
sq.rear=[0]
3. 简答题
3.1在栈的顺序存储结构下,进栈(向栈中插入元素)的操作步骤是什么(用什么语言描述)?退栈(从栈中删除元素)的操作步骤是哪些?
答:进栈操作是先将栈顶指针加1后,再将待插入元素入栈,退栈操作则是先取出栈顶元素,在使栈顶指针减1。
3.2有循环队列cq(最大长度QueueSize,rear和front分别为队尾和队首指针)使用C语言表示的入队、出队操作时队首、队尾指针移动语句。
答:入队操作的指针移动语句为:cq.rear=(cq.rear+1)%QueueSize;
出队操作的指针移动语句为:cq.front=(cq.front+1)%QueueSize;
3.3如果编号为1,2,3的三辆列车进入一个栈式结构的站台,那么可能得到的三辆列车出站序列有哪些?不可能出现的序列是什么?
答:所有可能的出站顺序有:123,132,213,231,321,不可能是312,因为当3号车进站并出站后,站台上有1号车和2号车,不可能先出1号而后出2号。
3.4对于队列来说,出队操作和取队头有什么区别?
答:出队操作是删除队头元素(修改头指针)之后,再返回该删除元素值,而取队头操作仅仅是取出队头元素值返回,不修改队头指针。
3.5简述下面给出的算法的功能是什么?(假设栈元素为整数类型)
void ex31(SeqStack *s)
{
int A[80],i,n;
n=0;
while(!empty(S))
{
A[n]=pop(s);
n++;
}
for(i=0;i<n;i++)
push(S,A[i]);
}
此算法的功能是通过一个数组将一个栈中的所有元素逆置存放。
3.6简述下面给出的算法的功能是什么?(假设栈元素为整数类型)
void ex32(SeqStack *s,int c)
{
SeqStack
T;
int d;
while(!StackEmpty(S))
{
d=pop(S);
if(d!=c)
push(T,d);
}
while(!StackEmpty(T))
{
d=pop(T);
push(S,d);
}
}
该算法的功能是通过一个中间栈T,达到删除栈S中所有与变量C相同的元素。
3.7设长度为n的链队列用循环链表表示,若只设头指针则入队操作的时间复杂度是多少?若只设尾指针呢?
答:只设头指针的入队操作时间复杂度为O(n);只设尾指针的入队操作时间复杂度为O(1)
3.8简述栈的特点及与一般线性表的区别?
答:栈叫先进后出表或叫后进先出表。栈的插入和删除都从称为栈顶的一端进行,一般线性表可以在线性表的中间及两端进行插入和删除操作。
3.9简述队列的特点及与一般线性表的区别?
答:队列叫先进先出表(FIFO)或叫后进后出表,队列的插入只能在队列的一端进行,该端称为队尾。队列的删除只能从另一端进行,该端称为队头。一般线性表可以在线性表的中间及两端进行插入和删除操作。
3.10比较栈和队列的相同点与不同点
答:栈和队列都是加了限制的线性表,栈叫后进先出表,队列叫先进先出表。栈和队列的插入和删除运算都在端点进行,栈的插入与删除在同一端点,队列的插入与删除在不同的端点进行。栈与队列的元素个数都是可变的,同一个栈或同一个队列中的元素类型是一致的。
3.11写出下列程序段的输出结果
main()
{
Stack S;
char x,y;
InitStack(S);
x=’c’;y=’k’;
Push(S,x);
Push(S,’a’);
Push(S,y);
Pop(S,x);
Push(S,’t’);
Push(S,x);
Pop(S,x);
Push(S,’s’);
while(!StackEmpty(S))
{
Pop(S,y);
printf(y);
}
printf(x);
}
输出结果:stack
3.12简述下列算法的功能
algo(Stack
S)
{
int i,n,a[255];
n=0;
while(!StackEmpty(s))
{
n++;Pop(S,A[n]);}
for(i=1;i<=n;i++)
Push(S,A[i]);
}
借助数组将S栈内的元素倒置
3.13简述下列算法的功能
algo2(Stack S)
{
T;int d;
InitStack(T);
while(!StackEmpty(s))
{
Pop(S,d);
Push(T,d);
}
while(!StackEmpty(T))
{
Pop(T,d);
Push(S,d);
}
}
借助T栈将S栈内的元素倒置
4. 算法设计
4.1顺序栈的六种基本操作
voidInitStack(SeqStack
*S)
{
//将顺序栈置空
S->top=-1;}
intStackEmpty(SeqStack
*S)
{
return S->top==1;
}
intStackFull(SeqStack
*S)
{
return S->top==StackSize-1;
}
void
Push(SeqStack *S, DataType x)
{
if(StackFull(S))
Error(“Stack
overflow”);//上溢,退出运行
S->data[++S->top]=x;//栈顶指针加1后将x进栈
}
DataType
Pop(SeqStack *s)
{
if(StackEmpty(S))
Error(“Stack
underflow”);//下溢,退出运行
return S->data[S->top--];//栈顶元素返回后将栈顶指针减1
}
DataType StackTop(SeqStack *s)
{
if(StackEmpty(S))
Error(“Stack is empty”);
return S->data[S->top];
}
4.2循环队列基本算法
#define QueueSize 100
typedef char DataType
//DataType的类型依赖于具体应用
typedef Sturet{
int front; //头指针,队非空时指向队头元素
int rear; //尾指针,队非空时指向队尾元素的下一位置
int count; //计数器,记录队中元素总数
DataType data[QueueSize]
}CirQueue;
void
InitQueue(CirQueue *Q)
{
Q->count=0;
Q->count=0; //计数器置0}
intQueueEmpty(CirQueue
*Q)
{ return Q->count==0; //队列无元素为空}
intQueueFull(CirQueue
*Q)
{return
Q->count== QueueSize; //队中元素个数等于QueueSize时队满}
voidEnQueue(CirQueue
*Q, DataType x)
{if(QueueFull(Q))
Error(“Queue
overflow”);//队满上溢
Q->count++; //队列元素个数加1
Q->data[Q->rear]=x; //新元素插入队尾
Q->rear=(Q->rear+1)%QueueSize;
DataType
DeQueue(CirQueue *Q)
{DataType
temp;
if(QueueEmpty(Q))
Error(“Queue
underflow”); //队空下溢
temp=Q->data[Q->front];
Q->count--;
Q->front=(Q->front+1)%QueueSize;//循环意义下的头指针加1
return temp;}
DataType
QueueFront(CirQueue *Q)
{
if(QueueEmpty(Q))
Error(“Queue is empty.”);
return Q->data[Q->front;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。