栈和队列答案.docx
《栈和队列答案.docx》由会员分享,可在线阅读,更多相关《栈和队列答案.docx(34页珍藏版)》请在冰豆网上搜索。
栈和队列答案
若按教科书3.1.1节中图(b)所示铁道进行车厢调度(注意:
两侧铁道均为单向行驶道),则请回答:
(1)如果进站的车厢序列为123,则可能得到的出站车厢序列是什么?
(2)如果进站的车厢序列为123456,则能否得到435612和135426的出站序列,并请说明为什么不能得到或者如何得到(即写出以‘S’表示进栈和以‘X’表示出栈的栈操作序列)。
解:
(1)123231321213132
(2)可以得到135426的出站序列,但不能得到435612的出站序列。
因为4356出站说明12已经在栈中,1不可能先于2出栈。
简述栈和线性表的差别。
解:
线性表是具有相同特性的数据元素的一个有限序列。
栈是限定仅在表尾进行插入或删除操作的线性表。
写出下列程序段的输出结果(栈的元素类型SElemType为char)。
voidmain()
{
StackS;
charx,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
简述以下算法的功能(栈的元素类型SElemType为int)。
(1)statusalgo1(StackS)
{
inti,n,A[255];
n=0;
while(!
StackEmpty(S)){n++;Pop(S,A[n]);}
for(i=1;i<=n;i++)Push(S,A[i]);
}
(2)statusalgo2(StackS,inte)
{
StackT;intd;
InitStack(T);
while(!
StackEmpty(S)){
Pop(S,d);
if(d!
=e)Push(T,d);
}
while(!
StackEmpty(T)){
Pop(T,d);
Push(S,d);
}
}
解:
(1)栈中的数据元素逆置
(2)如果栈中存在元素e,将其从栈中清除
假设以S和X分别表示入栈和出栈的操作,则初态和终态均为空栈的入栈和出栈的操作序列可以表示为仅由S和X组成的序列。
称可以操作的序列为合法序列(例如,SXSX为合法序列,SXXS为非法序列)。
试给出区分给定序列为合法序列或非法序列的一般准则,并证明:
两个不同的合法(栈操作)序列(对同一输入序列)不可能得到相同的输出元素(注意:
在此指的是元素实体,而不是值)序列。
解:
任何前n个序列中S的个数一定大于X的个数。
设两个合法序列为:
T1=S……X……S……
T2=S……X……X……
假定前n个操作都相同,从第n+1个操作开始,为序列不同的起始操作点。
由于前n个操作相同,故此时两个栈(不妨为栈A、B)的存储情况完全相同,假设此时栈顶元素均为a。
第n+1个操作不同,不妨T1的第n+1个操作为S,T2的第n+1个操作为X。
T1为入栈操作,假设将b压栈,则T1的输出顺序一定是先b后a;而T2将a退栈,则其输出顺序一定是先a后b。
由于T1的输出为……ba……,而T2的输出顺序为……ab……,说明两个不同的合法栈操作序列的输出元素的序列一定不同。
试证明:
若借助栈由输入序列12…n得到的输出序列为
(它是输入序列的一个排列),则在输出序列中不可能出现这样的情形:
存在着i<
<
。
解:
这个问题和题比较相似。
因为输入序列是从小到大排列的,所以若
<
<
,则可以理解为通过输入序列
可以得到输出序列
,显然通过序列123是无法得到312的,参见题。
所以不可能存在着i<
<
。
按照四则运算加、减、乘、除和幂运算(↑)优先关系的惯例,并仿照教科书节例3-2的格式,画出对下列算术表达式求值时操作数栈和运算符栈的变化过程:
A-B×C/D+E↑F
解:
BC=GG/D=HA-H=IE^F=JI+J=K
步骤
OPTR栈
OPND栈
输入字符
主要操作
1
#
A-B*C/D+E^F#
PUSH(OPND,A)
2
#
A
-B*C/D+E^F#
PUSH(OPTR,-)
3
#-
A
B*C/D+E^F#
PUSH(OPND,B)
4
#-
AB
*C/D+E^F#
PUSH(OPTR,*)
5
#-*
AB
C/D+E^F#
PUSH(OPND,C)
6
#-*
ABC
/D+E^F#
Operate(B,*,C)
7
#-
AG
/D+E^F#
PUSH(OPTR,/)
8
#-/
AG
D+E^F#
PUSH(OPND,D)
9
#-/
AGD
+E^F#
Operate(G,/,D)
10
#-
AH
+E^F#
Operate(A,-,H)
11
#
I
+E^F#
PUSH(OPTR,+)
12
#+
I
E^F#
PUSH(OPND,E)
13
#+
IE
^F#
PUSH(OPTR,^)
14
#+^
IE
F#
PUSH(OPND,F)
15
#+^
IEF
#
Operate(E,^,F)
16
#+
IJ
#
Operate(I,+,J)
17
#
K
#
RETURN
试推导求解n阶梵塔问题至少要执行的move操作的次数。
解:
试将下列递推过程改写为递归过程。
voidditui(intn)
{
inti;
i=n;
while(i>1)
cout<}
解:
voidditui(intj)
{
if(j>1){
cout<ditui(j-1);
}
return;
}
试将下列递归过程改写为非递归过程。
voidtest(int&sum)
{
intx;
cin>>x;
if(x==0)sum=0;
else
{
test(sum);
sum+=x;
}
cout<}
解:
voidtest(int&sum)
{
Stacks;
InitStack(s);
intx;
do{
cin>>x;
Push(s,x);
}while(x>0);
while(!
StackEmpty(s)){
Pop(s,x);
sum+=x;
cout<}
DestoryStack(s);
}
简述队列和堆栈这两种数据类型的相同点和差异处。
解:
栈是一种运算受限的线性表,其限制是仅允许在表的一端进行插入和删除运算。
队列也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。
写出以下程序段的输出结果(队列中的元素类型QElemType为char)。
voidmain()
{
QueueQ;
InitQueue(Q);
charx=‘e’,y=‘c’;
EnQueue(Q,‘h’);
EnQueue(Q,‘r’);
EnQueue(Q,y);
DeQueue(Q,x);
EnQueue(Q,x);
DeQueue(Q,x);
EnQueue(Q,‘a’);
While(!
QueueEmpty(Q))
{
DeQueue(Q,y);
cout<}
cout<}
解:
char
简述以下算法的功能(栈和队列的元素类型均为int)。
voidalgo3(Queue&Q)
{
StackS;
intd;
InitStack(S);
while(!
QueueEmpty(Q))
{
DeQueue(Q,d);
Push(S,d);
}
while(!
StackEmpty(S))
{
Pop(S,d);
EnQueue(Q,d);
}
}
解:
队列逆置
若以1234作为双端队列的输入序列,试分别求出满足以下条件的输出序列:
(1)能由输入受限的双端队列得到,但不能由输出受限的双端队列得到的输出序列。
(2)能由输出受限的双端队列得到,但不能由输入受限的双端队列得到的输出序列。
(3)既不能由输入受限的双端队列得到,也不能由输出受限的双端队列得到的输出序列。
假设以顺序存储结构实现一个双向栈,即在一维数组的存储空间中存在着两个栈,它们的栈底分别设在数组的两个端点。
试编写实现这个双向栈tws的三个操作:
初始化inistack(tws)、入栈push(tws,i,x)和出栈pop(tws,i)的算法,其中i为0或1,用以分别指示设在数组两端的两个栈,并讨论按过程(正/误状态变量可设为变参)或函数设计这些操作算法各有什么有缺点。
解:
classDStack{
ElemType*top[2];
ElemType*p;
intstacksize;
intdi;
public:
DStack(intm)
{
p=newElemType[m];
if(!
p)exit(OVERFLOW);
top[0]=p+m/2;
top[1]=top[0];
stacksize=m;
}
~DStack(){deletep;}
voidPush(inti,ElemTypex)
{
di=i;
if(di==0){
if(top[0]>=p)*top[0]--=x;
elsecerr<<"Stackoverflow!
";
}
else{
if(top[1]
elsecerr<<"Stackoverflow!
";
}
}
ElemTypePop(inti)
{
di=i;
if(di==0){
if(top[0]elsecerr<<"Stackempty!
";
}else{
if(top[1]>top[0])return*top[1]--;
elsecerr<<"Stackempty!
";
}
returnOK;
}
};
2’-1’olor;
Push(s,g[][]);
while(!
StackEmpty(s)){
Pop(s,e);
CurPos=;
g[][].Color=FillColor;
g[][].Visited=1;
if!
g[+1][].Visited&&
g[+1][].Color==OldColor
)
Push(s,g[+1][]);
if>0&&
!
g[][].Visited&&
g[][].Color==OldColor
)
Push(s,g[][]);
if!
g[][+1].Visited&&
g[][+1].Color==OldColor
)
Push(s,g[][+1]);
if>0&&
!
g[][].Visited&&
g[][].Color==OldColor
)
Push(s,g[][]);
}
}
voidCreateGDS(ElemTypeg[M][N])
{
inti,j;
for(i=0;ifor(j=0;jg[i][j].=i;
g[i][j].=j;
g[i][j].Visited=0;
g[i][j].Color=0;
}
for(i=2;i<5;i++)
for(j=2;j<4;j++)
g[i][j].Color=3;
for(i=5;ifor(j=3;j<6;j++)
g[i][j].Color=3;
}
voidShowGraphArray(ElemTypeg[M][N])
{
inti,j;
for(i=0;ifor(j=0;jcout<cout<}
}
假设表达式有单字母变量和双目四则运算符构成。
试写一个算法,将一个通常书写形式且书写正确的表达式转换为逆波兰表达式。
解:
.#格式
voidInversePolandExpression(charBuffer[])
{
Stacks;
InitStack(s);
inti=0,j=0;
ElemTypee;
Push(s,Buffer[i]);
i++;
while(Buffer[i]!
='#'){
if(!
IsOperator(Buffer[i])){//是操作数
Buffer[j]=Buffer[i];
i++;
j++;
}
else{//是操作符
GetTop(s,e);
if(Prior(e,Buffer[i])){//当栈顶优先权高于当前序列时,退栈
Pop(s,e);
Buffer[j]=e;
j++;
}
else{
Push(s,Buffer[i]);
i++;
}
}
}
while(!
StackEmpty(s)){
Pop(s,e);
Buffer[j]=e;
j++;
}
}
StatusIsOpertor(charc)
{
char*p="#+-*/";
while(*p){
if(*p==c)
returnTRUE;
p++;
}
returnFALSE;
}
StatusPrior(charc1,charc2)
{
charch[]="#+-*/";
inti=0,j=0;
while(ch[i]&&ch[i]!
=c1)i++;
if(i==2)i--;//加和减可认为是同级别的运算符
if(i==4)i--;//乘和除可认为是同级别的运算符
while(ch[j]&&ch[j]!
=c2)j++;
if(j==2)j--;
if(j==4)j--;
if(i>=j)returnTRUE;
elsereturnFALSE;
}
如题的假设条件,试写一个算法,对以逆波兰式表示的表达式求值。
解:
charCalVal_InverPoland(charBuffer[])
{
StackOpnd;
InitStack(Opnd);
inti=0;
charc;
ElemTypee1,e2;
while(Buffer[i]!
='#'){
if(!
IsOperator(Buffer[i])){
Push(Opnd,Buffer[i]);
}
else{
Pop(Opnd,e2);
Pop(Opnd,e1);
c=Cal(e1,Buffer[i],e2);
Push(Opnd,c);
}
i++;
}
returnc;
}
charCal(charc1,charop,charc2)
{
intx,x1,x2;
charch[10];
ch[0]=c1;
ch[1]='\0';
x1=atoi(ch);
ch[0]=c2;
ch[1]='\0';
x2=atoi(ch);
switch(op){
case'+':
x=x1+x2;
break;
case'-':
x=x1-x2;
break;
case'*':
x=x1*x2;
break;
case'/':
x=x1/x2;
break;
default:
break;
}
itoa(x,ch,10);
returnch[0];
}
如题的假设条件,试写一个算法,判断给定的非空后缀表达式是否为正确的逆波兰表达式,如果是,则将它转化为波兰式。
解:
#include<>
#include<>
#include<>
#include"d:
\VC99\"
typedefcharARRAY[30];
typedefARRAYElemType;
typedefstructNodeType{
ElemTypedata;
NodeType*next;
}NodeType,*LinkType;
typedefstruct{
LinkTypetop;
intsize;
}Stack;
voidInitStack(Stack&s);
StatusPush(Stack&s,ElemTypee);
StatusPop(Stack&s,ElemTypee);
StatusIsOperator(charc);
StatusStackEmpty(Stacks);
StatusInvToFroPoland(chara[]);
intmain()
{
chara[30];
cout<<"请输入逆波兰算术表达式字符序列:
";
cin>>a;
if(InvToFroPoland(a))cout<elsecout<<"输入逆波兰算术表达式字符序列错误!
";
return0;
}
StatusInvToFroPoland(chara[])
{
Stacks;
InitStack(s);
inti=0;
ElemTypech;
ElemTypec1;
ElemTypec2;
while(a[i]!
='#'){
if(!
IsOperator(a[i])){
if(a[i]>='0'&&a[i]<='9'){
ch[0]=a[i];ch[1]='\0';
Push(s,ch);
}
elsereturnFALSE;
}
else{
ch[0]=a[i];
ch[1]='\0';
if(!
StackEmpty(s)){
Pop(s,c2);
if(!
StackEmpty(s)){
Pop(s,c1);
strcat(ch,c1);
strcat(ch,c2);
Push(s,ch);
}
elsereturnFALSE;
}
elsereturnFALSE;
}
i++;
}
if(!
StackEmpty(s)){
Pop(s,c1);
strcpy(a,c1);
}
elsereturnFALSE;
if(!
StackEmpty(s))returnFALSE;
returnOK;
}
voidInitStack(Stack&s)
{
=NULL;
=0;
}
StatusPush(Stack&s,ElemTypee)
{
LinkTypep;
p=newNodeType;
if(!
p)exit(OVERFLOW);
p->next=;
=p;
strcpy(p->data,e);
++;
returnOK;
}
StatusPop(Stack&s,ElemTypee)
{
LinkTypep;
if{
strcpy(e,>data);
p=;
=p->next;
deletep;
;
}
returnOK;
}
StatusStackEmpty(Stacks)
{
if==0)returnTRUE;
elsereturnFALSE;
}
StatusIsOperator(charc)
{
char*p="#+-*/";
while(*p){
if(*p==c)
returnTRUE;
p++;
}
returnFALSE;
}
试编写如下定义的递归函数的递归算法,并根据算法画出求g(5,2)时栈的变化过程。
解:
intg(intm,intn);
intmain()
{
intm,n;
cout<<"请输入m和n的值:
";
cin>>m>>n;
if(n>=0)cout<elsecout<<"NoSolution!
";
return0;
}
intg(intm,intn)
{
if(m>0)
return(g(m-1,2*n)+n);
elsereturn0;
}
假设主函数的返回地址为0,递归函数3条语句的地址分别为1、2、3。
3
0
64
3
1
32
3
2
16
3
3
8
3
4
4
0
5
2
试写出求递归函数F(n)的递归算法,并消除递归:
解:
#include<>
#defineN20
intmain()
{
inti;
inta[N];
intn;
cout<<"请输入n:
";
cin>>n;
for(i=0;iif(i<1)a[i]=1;
elsea[i]=i*a[i/2];
}
cout<return0;
}
求解平方根
的迭代函数定义如下:
其中,p是A的近似平方根,e是结果允许误差。
试写出相应的递归算法,并消除递归。
解:
#include<>
doubleSqrt(double