第三章 栈和队列.docx
《第三章 栈和队列.docx》由会员分享,可在线阅读,更多相关《第三章 栈和队列.docx(31页珍藏版)》请在冰豆网上搜索。
![第三章 栈和队列.docx](https://file1.bdocx.com/fileroot1/2023-4/18/b04a7776-caa2-44a1-a0f6-76ba9d3debd0/b04a7776-caa2-44a1-a0f6-76ba9d3debd01.gif)
第三章栈和队列
第三章 栈和队列
一、内容提要
1.从数据结构角度讲,栈和队列也是线性表,其操作是线性表操作的子集,属操作受限的线性表。
但从数据类型的角度看,它们是和线性表大不相同的重要抽象数据类型。
2.栈的定义及操作。
栈是只准在一端进行插入和删除操作的线性表,该端称为栈的顶端。
3.栈的顺序和链式存储结构,及在这两种结构下实现栈的操作。
4.栈的应用:
表达式求值,递归过程及消除递归。
5.队列的定义及操作,队列的删除在一端(尾),而插入则在队列的另一端(头)。
因此在两种存储结构中,都需要队头和队尾两个指针。
6.链队列空的条件是首尾指针相等,而循环队列满的条件的判定,则有队尾加1等于
队头和设标记两种方法。
二、学习重点
1.栈和队列操作在两种存储结构下的实现。
2.中缀表达式转成前缀、后缀表达式并求值。
3.用递归解决的问题:
定义是递归的,数据结构是递归的,及问题的解法是递归的,
掌握典型问题的算法。
4. 链队列删除时为空的处理(令队尾指针指向队头)。
特别是仅设尾指针的循环链队
列的各种操作的实现。
5. 循环队列队空定义为队头指针等于队尾指针,队满则可用一个单元(教材中所示)
及设标记办法(下面例题)。
这里特别注意取模运算。
6. 在后续章节中要注意栈和队列的应用,如串中心对称的判定,二叉树遍历的递归
和非递归算法,图的深度优先遍历等都用到栈,而树的层次遍历、图的宽度优先遍
历等则用到队列。
三、例题解析
1.两栈共享一向量空间,编写入栈和出栈算法。
TYPE
TwoWayStack=RECORD{双栈共享一向量空间}
elem:
ARRAY[1..m]OFelemtype;
top:
ARRAY[0..1]OF0..m+1;{两个栈顶指针}
END;
#definem1000
Typedefstruct
{elemtypeelem[m];
inttop[2];
}*TwoWayStack;
inistack(TwoWayStacktws){初始化}
//初始化双向栈tws为空
{tws->top[0]=-1;{左端栈指针}
tws->top[1]=m;{右端栈指针}
}{inistack}
PUSH(TwoWayStacktws,intI,elemtypex,intofw)
{若双向栈tws不满,则将x插入到i端,成功时ofw为true,失败为false}
{IF((tws->top[1]-tws.top[0])!
=1)
//栈未满
Swithi
{case0:
tws->top[0]=tws->top[0]+1;tws->elem[tws->top[0]]=x;ofw=1;
case1:
tws->top[1]=tws->top[1]-1;tws->elem[tws->top[1]]=x;ofw=1
}
ELSEofw=0;//栈满
}//endpush
intPOP(TwoWayStacktws,intI,elemtype&x,intunderflow)
//若双向栈tws非空,则将i端退栈,栈空时underflow为true
{switchi
{case0:
IF(tws->top[0]==-1)//栈空
{underflow=1;return(underflow);}
ELSE{tws->top[0]=tws.top[0]-1;
x=tws->elem[tws->top[0]+1;
}//弹出元素
}
case1:
IF(tws->top[1]==m)//栈空
{underflow=1;return(underflow);}
ELSE{tws->top[1]=tws->top[1]+1;
x=tws->elem[tws.top[1]-1];//弹出元素
}
}
}//endpop
【讨论】上面算法中用0和1代表两端,且按操作在哪端来分两种情况进行讨论,逻辑清楚。
也可用一个公式表示插入(进栈)和删除(退栈)指针位置。
例如,插入时top=top+1-2*i,删除时top=top-1+2*i。
表达简洁,但不如上面清楚易读。
2.将中缀表达式转换成后缀表达式,并进行表达式求值。
Stringtrnssufix(stringexp1)
//本算法将中缀表达式exp1转为后缀表达式exp2,使用运算符栈s
//算法基本思想是依次从中缀表达式读入字符w:
若w是变量,直接送入结果表达式,若w是运算符,则与栈顶运算符比较,若级别高,则进栈;若低,则栈顶元素退栈,并送入结果表达式,再取栈顶运算符比较,重复以上步骤;若w=’)’,则栈元素依次退栈,并送入结果表达式,直至')'退栈
{stringexp2;stacks;
charw;
initstring(exp2);initstack(s);push(s,’#’);
//op=['+','-','*','/','(',')','#']操作符集合
scanf("%c",&w);
WHILE(!
((w=='#')&&(GETTOP(OPTR)=='#')))
IF(!
in(w,op)){insert(exp2,w);scanf("%c",&w);}
ELSEswitch(precede(GETTOP(s),w))
{case'<':
PUSH(S,w);scanf("%c",&w);}
case'=':
IF(w==')')//遇右括号后,运算符退栈并送结果表达式,直至左括号
x=POP(S);
WHILE(x!
='('){insert(exp2,x);x=POP(S);}
scanf("%c",&w);
case'>':
b=POP(S);insert(exp2,b);
}
return(exp2);}
operandtypesufixeval()
//算法基本思想是逐字符从左到右顺序读入后缀表达式。
若读入的字符w是数,则直接压入栈sn中;若w是运算符,则与栈顶运算符比较,若级别高,则进栈;否则,从运算数栈弹出两个操作数,和从运算符栈弹出的一个运算符进行相应运算,结果存入操作数栈中。
w运算符再与栈顶运算符比较优先级。
直至后缀表达式处理完毕。
这时sn栈中只剩一个数,即表达式结果。
{stacks,sn;
initstring(sn);initstack(s);
//op=['+','-','*','/','(',')','#'];操作符集合
scanf("%c",&w);//从左到右顺序读入后缀表达式
WHILE(!
((w=='#')&&(GETTOP(OPTR)=='#')))
{IF(!
in(w,op)){PUSH(sn,w);scanf("%c",&w);}
ELSEswitch(precede(GETTOP(s),w))
{case'<':
PUSH(s,w);scanf("%c",&w);}
case'>':
{a=POP(sn);b=POP(sn);theta=POP(s);
PUSH(sn,operate(athetab));}
}
return(gettop(sn));
}//endsufixeval
3.用设标记来判定循环队列满,编写入队和出队的算法。
//本算法用设标记tag的办法,解决循环队列队满和队列空的判断问题,tag=0表示队列空,tag=1表示队列不空
#definem1000
typedefstruct
{elemtypeelem[m];
intrear,front;
inttag;
}cyclicqueue;//设头尾指针和标志域的循环队列,tag为表示空,tag为1表示非空
INITQUEDE(cyclicqueue&cq)//初始化
{cq.tag=0;cq.tear=cq.front=0;
}
ENQUEUE(cyclicqueue&cq,elemtypex)
//cq是由头尾指针和标志域的循环队列,本算法是入队操作,若队列不满,则将x插入到队尾
{IF((cq.tag==1)&&(cq.front==cq.rear))
return(0);//队满
ELSE{cq.rear=(cq.rear+1)%m;
cq.elem(cq.rear)=r;
IF(cq.tag==0)cq.tag=1;//由空变不空标记
}
}
DELQUEUE(cyclicqueue&cq)
//cq是由头尾指针和标志域的循环队列,本算法是出队操作,若队列非空 则将队头元素出队
{IF(cq.tag==0)
return(0);//队空
ELSE{cq.front=(cq.front+1)%m;
IF(cq.front==cq.rear)cq.tag=0;//队空
}
}
#definem1000
typedefstruct
{elemtypeelem[m];
intrear;
intlength;
}cyclicqueue;//只设尾指针和队列长度的循环队列
INIT_queue(cyclicqueue&q)//初始化
{q.rear=-1;q.length=0;}
intadd_queue(cyclicqueue&q,elemtypex)
//q是由尾指针和长度标志的循环队列,本算法是入队操作,若队列不满,将x插入到队尾
{IF(q.length==m)
return(0);//队列满
ELSE{q.rear=(q.rear+1)%m;
q.elem[q.rear]=x;
q.length;=q.length+1;
return
(1);//入队成功
}
}
intdd_queue(cyclicqueue&q,elemtype&x)
//q是由尾指针和长度标志的循环队列,本算法是出队操作,若队列不空,将将队头元素出列,并赋给x,队长度减1
{IF(q.length==0)
return(0);//队空
ELSE{front=(q.rear-q.length+1+m)%m;
x=q.elem[front];
q.length=q.length-1;
return
(1);}
}
四、基本题
(一)选择题
1.对于栈操作数据的原则是()。
【青岛大学2001五、2(2分)】
A.先进先出B.后进先出C.后进后出D.不分顺序
2.在作进栈运算时,应先判别栈是否(①),在作退栈运算时应先判别栈是否(②)。
当栈中元素为n个,作进栈运算时发生上溢,则说明该栈的最大容量为(③)。
为了增加内存空间的利用率和减少溢出的可能性,由两个栈共享一片连续的内存空间时,应将两栈的(④)分别设在这片内存空间的两端,这样,当(⑤)时,才产生上溢。
①,②:
A.空B.满C.上溢D.下溢
③:
A.n-1B.nC.n+1D.n/2
④:
A.长度B.深度C.栈顶D.栈底
⑤:
A.两个栈的栈顶同时到达栈空间的中心点.
B.其中一个栈的栈顶到达栈空间的中心点.
C.两个栈的栈顶在栈空间的某一位置相遇.
D.两个栈均不空,且一个栈的栈顶到达另一个栈的栈底.
【上海海运学院1997二、1(5分)】【上海海运学院1999二、1(5分)】
3.一个栈的输入序列为123…n,若输出序列的第一个元素是n,输出第i(1<=i<=n)个元素是()。
A.不确定B.n-i+1C.iD.n-i
【中山大学1999一、9(1分)】
4.若一个栈的输入序列为1,2,3,…,n,输出序列的第一个元素是i,则第j个输出元素是()。
A.i-j-1B.i-jC.j-i+1D.不确定的
【武汉大学2000二、3】
5.若已知一个栈的入栈序列是1,2,3,…,n,其输出序列为p1,p2,p3,…,pN,若pN是n,则pi是()。
A.iB.n-iC.n-i+1D.不确定
【南京理工大学2001一、1(1.5分)】
6.有六个元素6,5,4,3,2,1的顺序进栈,问下列哪一个不是合法的出栈序列?
()
A.543612B.453126C.346521D.234156
【北方交通大学2001一、3(2分)】
7.设栈的输入序列是1,2,3,4,则()不可能是其出栈序列。
【中科院计算所2000一、10(2分)】
A.1,2,4,3,B.2,1,3,4,C.1,4,3,2,
D.4,3,1,2,E.3,2,1,4,
8.一个栈的输入序列为12345,则下列序列中不可能是栈的输出序列的是()。
A.23415B.54132C.23145D.15432
【南开大学2000一、1】【山东大学2001二、4(1分)】【北京理工大学2000一、2(2分)】
9.设一个栈的输入序列是1,2,3,4,5,则下列序列中,是栈的合法输出序列的是()。
A.51234B.45132C.43125D.32154
【合肥工业大学2001一、1(2分)】
10.某堆栈的输入序列为a,b,c,d,下面的四个序列中,不可能是它的输出序列的是()。
A.a,c,b,dB.b,c,d,aC.c,d,b,aD.d,c,a,b
【北京航空航天大学2000一、3(2分)】【北京邮电大学1999一、3(2分)】
11.设abcdef以所给的次序进栈,若在进栈操作时,允许退栈操作,则下面得不到的序列为()。
A.fedcbaB.bcafedC.dcefbaD.cabdef
【南京理工大学1996一、9(2分)】
12.设有三个元素X,Y,Z顺序进栈(进的过程中允许出栈),下列得不到的出栈排列是()。
A.XYZB.YZXC.ZXYD.ZYX
【南京理工大学1997一、5(2分)】
13.输入序列为ABC,可以变为CBA时,经过的栈操作为()【中山大学1999一、8(1分)】
A.push,pop,push,pop,push,popB.push,push,push,pop,pop,pop
C.push,push,pop,pop,push,popD.push,pop,push,push,pop,pop
14.若一个栈以向量V[1..n]存储,初始栈顶指针top为n+1,则下面x进栈的正确操作是()。
A.top=top+1;V[top]=xB.V[top]=x;top=top+1
C.top=top-1;V[top]=xD.V[top]=x;top=top-1
【南京理工大学1998一、13(2分)】
15.若栈采用顺序存储方式存储,现两栈共享空间V[1..m],top[i]代表第i个栈(i=1,2)栈顶,栈1的底在v[1],栈2的底在V[m],则栈满的条件是()。
A.|top[2]-top[1]|=0B.top[1]+1=top[2]C.top[1]+top[2]=mD.top[1]=top[2]
【南京理工大学1999一、14(1分)】
16.栈在()中应用。
【中山大学1998二、3(2分)】
A.递归调用B.子程序调用C.表达式求值D.A,B,C
17.一个递归算法必须包括()。
【武汉大学2000二、2】
A.递归部分B.终止条件和递归部分C.迭代部分D.终止条件和迭代部分
19.表达式a*(b+c)-d的后缀表达式是()。
【南京理工大学2001一、2(1.5分)】
A.abcd*+-B.abc+*d-C.abc*+d-D.-+*abcd
20.表达式3*2^(4+2*2-6*3)-5求值过程中当扫描到6时,对象栈和算符栈为(),其中^为乘幂。
A.3,2,4,1,1;(*^(+*-B.3,2,8;(*^-C.3,2,4,2,2;(*^(-D.3,2,8;(*^(-
【青岛大学2000五、5(2分)】
21.设计一个判别表达式中左,右括号是否配对出现的算法,采用()数据结构最佳。
A.线性表的顺序存储结构B.队列C.线性表的链式存储结构D.栈
【西安电子科技大学1996一、6(2分)】
22.用链接方式存储的队列,在进行删除运算时()。
【北方交通大学2001一、12(2分)】
A.仅修改头指针B.仅修改尾指针C.头、尾指针都要修改D.头、尾指针可能都要修改
23.用不带头结点的单链表存储队列时,其队头指针指向队头结点,其队尾指针指向队尾结点,则在进行删除操作时()。
【北京理工大学2001六、3(2分)】
A.仅修改队头指针B.仅修改队尾指针
C.队头、队尾指针都要修改D.队头,队尾指针都可能要修改
24.递归过程或函数调用时,处理参数及返回地址,要用一种称为()的数据结构。
A.队列B.多维数组C.栈D.线性表
【福州大学1998一、1(2分)】
25.假设以数组A[m]存放循环队列的元素,其头尾指针分别为front和rear,则当前队列中的元素个数为()。
【北京工商大学2001一、2(3分)】
A.(rear-front+m)%mB.rear-front+1C.(front-rear+m)%mD.(rear-front)%m
26.循环队列A[0..m-1]存放其元素值,用front和rear分别表示队头和队尾,则当前队列中的元素数是()。
【南京理工大学2001一、5(1.5分)】
A.(rear-front+m)%mB.rear-front+1C.rear-front-1D.rear-front
27.循环队列存储在数组A[0..m]中,则入队时的操作为()。
【中山大学1999一、6(1分)】
A.rear=rear+1B.rear=(rear+1)%(m-1)
C.rear=(rear+1)%mD.rear=(rear+1)%(m+1)
28.若用一个大小为6的数组来实现循环队列,且当前rear和front的值分别为0和3,当从队列中删除一个元素,再加入两个元素后,rear和front的值分别为多少?
()【浙江大学1999四、1(4分)】
A.1和5B.2和4C.4和2D.5和1
29.已知输入序列为abcd经过输出受限的双向队列后能得到的输出序列有()。
A.dacbB.cadbC.dbcaD.bdacE.以上答案都不对
【西安交通大学1996三、3(3分)】
30.若以1234作为双端队列的输入序列,则既不能由输入受限的双端队列得到,也不能由输出受限的双端队列得到的输出序列是()。
【西安电子科技大学1996一、5(2分)】
A.1234B.4132C.4231D.4213
31.最大容量为n的循环队列,队尾指针是rear,队头是front,则队空的条件是()。
A.(rear+1)%n=frontB.rear=front
C.rear+1=frontD.(rear-l)%n=front
【南京理工大学1999一、16(2分)】
32.栈和队列的共同点是()。
【燕山大学2001一、1(2分)】
A.都是先进先出B.都是先进后出
C.只允许在端点处插入和删除元素D.没有共同点
33.栈的特点是(①),队列的特点是(②),栈和队列都是(③)。
若进栈序列为1,2,3,4则(④)不可能是一个出栈序列(不一定全部进栈后再出栈);若进队列的序列为1,2,3,4则(⑤)是一个出队列序列。
【北方交通大学1999一、1(5分)】
①,②:
A.先进先出B.后进先出C.进优于出D.出优于进
③:
A.顺序存储的线性结构B.链式存储的线性结构
C.限制存取点的线性结构D.限制存取点的非线性结构
④,⑤:
A.3,2,1,4B.3,2,4,1C.4,2,3,1D.4,3,2,1F.1,2,3,4G.1,3,2,4
34.栈和队都是()【南京理工大学1997一、3(2分)】
A.顺序存储的线性结构B.链式存储的非线性结构
C.限制存取点的线性结构D.限制存取点的非线性结构
35.设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5和e6依次通过栈S,一个元素出栈后即进队列Q,若6个元素出队的序列是e2,e4,e3,e6,e5,e1则栈S的容量至少应该是()。
A.6B.4C.3D.2
【南京理工大学2000一、6(1.5分)】
36.用单链表表示的链式队列的队头在链表的()位置。
【清华大学1998一、1(2分)】
A.链头B.链尾C.链中
37.依次读入数据元素序列{a,b,c,d,e,f,g}进栈,每进一个元素,机器可要求下一个元素进栈或弹栈,如此进行,则栈空时弹出的元素构成的序列是以下哪些序列?
【哈尔滨工业大学2000七(8分)】
A.{d,e,c,f,b,g,a}B.{f,e,g,d,a,c,b}
C.{e,f,d,g,b,c,a}D.{c,d,b,e,f,a,g}
(二)判断题
1.消除递归不一定需要使用栈,此说法()
【中科院计算所1998二、2(2分)】【中国科技大学1998二、2(2分)】
2.栈是实现过程和函数等子程序所必需的结构。
()【合肥工业大学2000二、2(1分)】
3.两个栈共用静态存储空间,对头使用也存在空间溢出问题。
()【青岛大学2000四、2(1分)】
4.两个栈共享一片连续内存空间时,为提高内存利用率,减少溢出机会,应把两个栈的栈底分别设在这片内存空间的两端。
()【上海海运学院1998一、4(1分)】
5.即使对不含相同元素的同一输入序列进行两组不同的合法的入栈和出栈组合操作,所得的输出序列也一定相同。
()【北京邮电大学1999二、4(2分)】
6.有n个数顺序(依次)进栈,出栈序列有Cn种,Cn=[1/(n+1)]*(2n)!
/[(n!
)*(n!
)]。
()
【北京邮电大学1998一、3(2分)】
7.栈与队列是一种特殊操作的线性表。
()【青岛大学2001四、3(1分)】
8.若输入序列为1,2,3,4,5,6,则通过一个栈可以输出序列3,2,5,6,4,1.()
【上海海运学院1995一、2(1分)1997一、3(1分)】
9.栈和队列都是限制存取点的线性结构。
()【中科院软件所1999六、(5)(2分)】
10.若输入序列为1,2,3,4,5,6,则通过一个栈可以输出序列1,5,4,6,2,3。
()
【上海海运学院1999一、3(1分)】
11.任何一个递归过程都可以转换成非递归过程。
( )【上海交通大学1998一、3(1分)】
12.只有那种使用了局部变量的递归过程在转换成非递归过程时才必须使用栈。
( )
【上海交通大学1998一、4(1分)】
13.队列是一种插入与删除操作分别在表的两端进行的线性表,