💡 <03 栈和队列>习题(非代码部分)

This commit is contained in:
康建伟
2019-11-04 23:02:09 +08:00
parent a9ed1f40bb
commit 11b529b069
13 changed files with 372 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,372 @@
# 第3章 栈和队列
## 一、基础知识题
### 3.1 若按教科书3.1.1节中图3.1(b)所示铁道进行车厢调度(注意:两侧铁道均为单向行驶道),则请回答:
![3.1](_v_images/20181125024206496_10580.png)
##### (1) 如果进站的车厢序列为123则可能得到的出站车厢序列是什么
> 1123 231 321 213 132
##### (2) 如果进站的车厢序列为123456则能否得到435612和135426的出站序列并请说明为什么不能得到或者如何得到即写出以S表示进栈和以X表示出栈的栈操作序列
> 2可以得到135426的出站序列其相应操作为SXSSXSSXXXSX。不能得到435612的出站序列。因为4356出站说明12已经在栈中1不可能先于2出栈。
### 3.2 简述栈和线性表的差别。
> 线性表是一组具有相同特性的数据元素的一个有限序列。栈是限定仅在表尾进行插入或删除操作的线性表。
### 3.3 写出下列程序段的输出结果栈的元素类型SElemType为char
```c
void 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.4 简述以下算法的功能栈的元素类型SElemType为int
**(1)**
```c
status algo1(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]);
}
```
> 栈中的数据元素逆置。
**(2)**
```c
status algo2(Stack S,int e)
{
Stack T;
int d;
InitStack(T);
while(!StackEmpty(S))
{
Pop(S, d);
if(d!=e)
Push(T, d);
}
while(!StackEmpty(T))
{
Pop(T, d);
Push(S, d);
}
}
```
> 如果栈中存在元素e将其从栈中删除。
### 3.5 假设以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个操作为ST2的第n+1个操作为X。T1为入栈操作假设将b压栈则T1的输出顺序一定是先b后a而T2将a退栈则其输出顺序一定是先a后b。由于T1的输出为……ba……而T2的输出顺序为……ab……说明两个不同的合法栈操作序列的输出元素的序列一定不同。
### 3.6 试证明若借助栈由输入序列12…n得到的输出序列为p1p2…pn(它是输入序列的一个排列)则在输出序列中不可能出现这样的情形存在着i<j<k使pj<pk<pi。
> 这个问题和3.1题比较相似。因为输入序列是从小到大排列的所以若pj<pk<pi则可以理解为通过输入序列pjpkpi可以得到输出序列pipjpk显然通过序列123是无法得到312的参见3.1题。所以不可能存在着i<j<k使pj<pk<pi。
### 3.7 按照四则运算加、减、乘、除和幂运算(↑)优先关系的惯例并仿照教科书3.2节例3-2的格式画出对算术表达式 A-B×C/D+E↑F 求值时操作数栈和运算符栈的变化过程:
> BC=G G/D=H A-H=I E^F=J I+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| `#-`|`A B`| `*C/D+E^F#` |`PUSH(OPTR,*)`|
|5| `#-*`|`A B`| `C/D+E^F#`|`PUSH(OPND,C)`|
|6|`#-*`|`A B C`|`/D+E^F#`|`Operate(B,*,C)`|
|7|`#-`|`A G`|`/D+E^F#`|`PUSH(OPTR,/)`|
|8|`#-/`|`A G`| `D+E^F#`|`PUSH(OPND,D)`|
|9|`#-/`|`A G D`|`+E^F#`|`Operate(G,/,D)`|
|10|`#-`|`A H`|`+E^F#`|`Operate(A,-,H)`|
|11|`#`|`I`|`+E^F#`|`PUSH(OPTR,+)`|
|12|`#+`|`I`| `E^F#`|`PUSH(OPND,E)`|
|13|`#+`|`I E`| `^F#` |`PUSH(OPTR,^)`|
|14|`#+^`|`I E`|`F#`|`PUSH(OPND,F)`|
|15|`#+^`|`I E F`| `#` |`Operate(E,^,F)`|
|16|`#+`|`I J`| `#` |`Operate(I,+,J)`|
|17|`#`|`K`| `#` |`RETURN`|
### 3.8 试推导求解n阶梵塔问题至少要执行的move操作的次数。
> 设至少要执行M(n)次move操作
> ![3.8.1](_v_images/20181125025136643_3363.png)
> 解此方程可得 ![3.8.2](_v_images/20181125025200738_6113.png)。
### 3.9 试将下列递推过程改写为递归过程。
```c
void ditui(int n)
{
int i;
i = n;
while(i>1)
cout<<i--;
}
```
> 递归过程如下:
>
> void digui(int j)
> {
> &nbsp;&nbsp;&nbsp;&nbsp;if(j>1)
> &nbsp;&nbsp;&nbsp;&nbsp;{
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout<<j;
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;digui(j-1);
> &nbsp;&nbsp;&nbsp;&nbsp;}
> &nbsp;&nbsp;&nbsp;&nbsp;return;
> }
### 3.10 试将下列递归过程改写为非递归过程。
```c
void test(int &sum)
{
int x;
cin>>x;
if(x==0)
sum=0;
else
{
test(sum);
sum+=x;
}
cout<<sum;
}
```
> 非递归过程如下:
>
> void test(int &sum)
> {
> &nbsp;&nbsp;&nbsp;&nbsp;Stack s;
> &nbsp;&nbsp;&nbsp;&nbsp;int x;
> &nbsp;&nbsp;&nbsp;&nbsp;scanf(x);
> &nbsp;&nbsp;&nbsp;&nbsp;InitStack(s);
> &nbsp;&nbsp;&nbsp;&nbsp;while(x)
> &nbsp;&nbsp;&nbsp;&nbsp;{
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Push(S,x);
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scanf(x);
> &nbsp;&nbsp;&nbsp;&nbsp;}
> &nbsp;&nbsp;&nbsp;&nbsp;sum=0;
> &nbsp;&nbsp;&nbsp;&nbsp;printf(sum);
> &nbsp;&nbsp;&nbsp;&nbsp;while(Pop(S,x))
> &nbsp;&nbsp;&nbsp;&nbsp;{
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sum +=x;
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(sum);
> &nbsp;&nbsp;&nbsp;&nbsp;}
> }
>
### 3.11 简述队列和堆栈这两种数据类型的相同点和差异处。
> 栈是一种运算受限的线性表,其限制是仅允许在表的一端进行插入和删除运算。
> 队列也是一种运算受限的线性表,其限制是仅允许在表的一端进行插入,而在表的另一端进行删除。
### 3.12 写出以下程序段的输出结果队列中的元素类型QElemType为char
```c
void main()
{
Queue Q;
InitQueue(Q);
char x= 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<<y;
}
cout<<x;
}
```
> 输出结果char
### 3.13 简述以下算法的功能栈和队列的元素类型均为int
```c
void algo3(Queue &Q)
{
Stack S;
int d;
InitStack(S);
while(!QueueEmpty(Q))
{
DeQueue(Q, d);
Push(S, d);
}
while(!StackEmpty(S))
{
Pop(S, d);
EnQueue(Q, d);
}
}
```
> 功能:利用栈的特长进行队列逆置。
### 3.14 若以1234作为双端队列的输入序列试分别求出满足以下条件的输出序列
##### (1) 能由输入受限的双端队列得到,但不能由输出受限的双端队列得到的输出序列。
##### (2) 能由输出受限的双端队列得到,但不能由输入受限的双端队列得到的输出序列。
##### (3) 既不能由输入受限的双端队列得到,也不能由输出受限的双端队列得到的输出序列。
> 注:输入顺序确定,但是输入输出的方式不定,可以边输入边输出。
>
>14 1 3 2
>24 2 1 3
>34 2 3 1
>
> 提示不要穷举所有输入输出而是穷举1234可能组成的24种排列方式然后对每一种排列方式校验看是否满足题意。
## 二、算法设计题
### 3.15 假设以顺序存储结构实现一个双向栈即在一维数组的存储空间中存在着两个栈它们的栈底分别设在数组的两个端点。试编写实现这个双向栈tws的三个操作初始化inistack(tws)、入栈push(tws,i,x)和出栈pop(tws,i)的算法其中i为0或1用以分别指示设在数组两端的两个栈并讨论按过程(正/误状态变量可设为变参)或函数设计这些操作算法各有什么有缺点。
----------
### 3.16 假设如题3.1所属火车调度站的入口处有n节硬席或软席车厢分别以H和S表示等待调度试编写算法输出对这n节车厢进行调度的操作即入栈或出栈操作序列以使所有的软席车厢都被调整到硬席车厢之前。
![3.16](_v_images/20181125030309014_31323.png)
----------
### 3.17 试写一个算法,识别一次读入的一个以@为结束符的字符序列是否为形如序列1&序列2模式的字符序列。其中序列1和序列2中都不含字符&且序列2是序列1的逆序列。例如a+b&b+a是属该模式的字符序列1+3&3-1则不是。
----------
### 3.18 试写一个判别表达式中开、闭括号是否配对出现的算法。
----------
### 3.19 假设一个算数表达式中可以包含三种符号:圆括号“(”和“)”、方括号“[”和“]”和花括号“{”和“}”,且这三种括号可按任意的次序嵌套使用(如:…[…{…}…[…]…]…[…]…(…)…)。编写判别给定表达式中所含括号是否正确配对出现的算法(已知表达式已存入数据元素为字符的顺序表中)。
----------
### 3.20 假设以二维数组g(1…m, 1…n)表示一个图像区域g[i,j]表示该区域中点(i,j)所具颜色其值为从0到k的整数。编写算法置换点(i0,j0)所在区域的颜色。约定和(i0,j0)同色的上、下、左、右的邻接点为同色区域的点。
----------
### 3.21 假设表达式有单字母变量(下面算法中将改为只有一位的数字)和双目四则运算符构成。试写一个算法,将一个通常书写形式且书写正确的表达式转换为逆波兰表达式。
----------
### 3.22 如题3.21的假设条件,试写一个算法,对以逆波兰式表示的表达式求值。
----------
### 3.23 如题3.21的假设条件,试写一个算法,判断给定的非空后缀表达式是否为正确的逆波兰表达式,如果是,则将它转化为波兰式。
----------
### 3.24 试编写如下定义的递归函数的递归算法并根据算法画出求g(5,2)时栈的变化过程。
![3.24](_v_images/20181125032559435_18150.png)
----------
### 3.25 试写出求递归函数F(n)的递归算法,并消除递归:
![3.25](_v_images/20181125032637164_29470.png)
----------
### 3.26 求解平方根![3.26.1](_v_images/20181125032709496_14427.png)的迭代函数定义如下:
![3.26.2](_v_images/20181125032720114_19623.png)
### 其中p是A的近似平方根e是结果允许误差。试写出相应的递归算法并消除递归。
----------
### 3.27 已知Ackerman函数的定义如下
![3.27](_v_images/20181125032756850_24237.png)
##### (1) 写出递归算法;
##### (2) 写出非递归算法;
##### (3) 根据非递归算法画出求akm(2,1)时栈的变化过程。
----------
### 3.28 假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(注意不设头指针),试编写相应的队列初始化、入队列和出队列的算法。
----------
### 3.29 如果希望循环队列中的元素都能得到利用则需设置一个标志域tag并以tag的值为0和1来区分尾指针和头指针值相同时的队列状态是“空”还是“满”。试编写与此结构相应的入队列和出队列的算法并从时间和空间角度讨论设标志和不设标志这两种方法的使用范围如当循环队列容量较小而队列中每个元素占的空间较多时哪一种方法较好
----------
### 3.30 假设将循环队列定义为以域变量rear和length分别指示循环队列中队尾元素的位置和内含元素的个数。试给出此循环队列的队满条件并写出相应的入队列和出队列的算法在出队列的算法中要返回队头元素
### 3.32 试利用循环队列编写求k阶菲波那契序列中前n+1项的算法要求满足![3.32.1](_v_images/20181125033000185_2827.png)而![3.32.2](_v_images/20181125033016478_12557.png)其中max为某个约定的常数。注意本题所用循环队列的容量仅为k则在算法执行结束时留在循环队列中的元素应是所求k阶菲波那契序列中的最后k项
----------
### 3.31 假设称正读和反读都相同的字符序列为“回文”例如abbaabcba是回文abcdeababab则不是回文。试写一个算法判别读入的一个以@’为结束符的字符序列是否是“回文”。
----------
### 3.33 在顺序存储结构上实现输出受限的双端循环队列的入列和出列(只允许队头出列)算法。设每个元素表示一个待处理的作业,元素值表示作业的预计时间。入队列采取简化的短作业优先原则,若一个新提交的作业的预计执行时间小于队头和队尾作业的平均时间,则插入在队头,否则插入在队尾。
----------
### 3.34 假设在如教科书3.4.1节中图3.9所示的铁道转轨网的输入端有n节车厢硬座、硬卧和软卧分别以PH和S表示等待调度要求这三种车厢在输出端铁道上的排列次序为硬座P在前软卧S在中硬卧H在后。试利用输出受限只允许队头出列的双端队列对这n节车厢进行调度编写算法输出调度的操作序列分别以字符ED表示对双端队列的头端进行入队列和出队列的操作以字符A表示对双端队列的尾端进行入队列的操作。
![3.34](_v_images/20181125033143843_1638.png)
----------