习题部分
选择题
第一题
一个问题的递归算法求解和其相对应的非递归算法求解()
A. 递归算法通常高效一些 B. 非递归算法通常高效一些
C. 两者相同 D. 无法比较
第二题
执行()操作时,需要使用队列作为辅助存储空间
A. 查找散列(哈希)表 B. 广度优先搜索图
C. 前序(根)遍历二叉树 D. 深度优先搜索图
第三题
已知操作符包括‘+’‘-’‘’‘/’‘(’‘)’ 。将中缀表达式a+b-a((c+d)/e-f)+g转化为等价的后缀表达式ab+acd+e/f-*-g+时,用栈来存放暂时还不能确定运算次序的操作符。若栈初始时为空,则转换过程中同事保存在栈中的操作符的最大个数是()
A. 5 B. 7
C. 8 D. 11
第四题
假设栈初始为空,将中缀表达式a/b+(c*d-e*f)/g转化为等价的狗追表达式的过程中,当扫描到f时,栈中的元素依次是()
A. +(*- B. +(-* C. /+(*-* D. /+-*
解答部分
第一题
通常情况下,递归算法在计算机实际执行的过程中包含很多的重复计算,所以效率会低
第二题
图的广度优先搜索类似于树的层序遍历,同样需要借助于队列
第三题
考察栈在种猪表达式转化为后缀表达式中的应用。
将中缀表达式a+b-a*((c+d)/e-f)+g转换为相应的后缀表达式,需要根据操作符<op>
的优先级来进行栈的变化,我们用icp来表示当前扫描到的运算符ch的优先级,该运算符进栈后的优先级为isp,则运算符的优先级如下表所示:
(isp)是栈内优先(in stack priority)数,icp是栈外优先(in coming priority)数。
操作符 | # | ( | *,/ | +,- | ) |
---|---|---|---|---|---|
isp | 0 | 1 | 5 | 3 | 6 |
icp | 0 | 6 | 4 | 2 | 1 |
我们在表达式后面加上‘#’,表示表达式结束,具体换换过程如下:
步骤 | 扫描项 | 项类型 | 动作 | 栈内内容 | 输出 |
---|---|---|---|---|---|
isp | 0 | 1 | 5 | 3 | 6 |
icp | 0 | 6 | 4 | 2 | 1 |
0 | #进栈,读下一符号 | # | |||
1 | a | 操作数 | 直接输出 | # | a |
2 | + | 操作符 | isp(‘#’) < icp(‘+’),进栈 | #+ | |
3 | b | 操作数 | 直接输出 | #+ | b |
4 | - | 操作符 | isp(‘+’) > icp(‘-‘),退栈并输出 | # | + |
5 | isp(‘#’) < icp(‘-‘),进栈 | #- | |||
6 | a | 操作数 | 直接输出 | #- | a |
7 | * | 操作符 | isp(‘-‘) < icp(‘*’)进栈 | #-* | |
8 | ( | 操作符 | isp(‘*’) < icp(‘(‘),进栈 | #-*( | |
9 | ( | 操作符 | isp(‘(‘) < icp(‘(‘),进栈 | #-*(( | |
10 | c | 操作数 | 直接输出 | #-*(( | c |
11 | + | 操作符 | isp(‘(‘) < icp(‘+’),进栈 | #-*((+ | |
12 | d | 操作数 | 直接输出 | #-*((+ | d |
13 | ) | 操作符 | isp(‘+’) > icp(‘)’),退栈并输出 | #-*(( | + |
14 | isp(‘(‘) == icp(‘)’),直接退栈 | #-*( | |||
15 | / | 操作符 | isp(‘(‘) < icp(‘/’),进栈 | #-*(/ | |
16 | e | 操作数 | 直接输出 | #-*(/ | e |
17 | - | 操作符 | isp(‘/’) > icp(‘-‘),退栈并输出 | #-*( | / |
18 | isp(‘(‘) < icp(‘-‘),进栈 | #-*(- | |||
19 | f | 操作数 | 直接输出 | #-*(- | f |
20 | ) | 操作符 | isp(‘-‘) > icp(‘)’),退栈并输出 | #-*( | - |
21 | isp(‘(‘) == icp(‘)’),直接退栈 | #-* | |||
22 | + | 操作符 | isp(‘*’) > icp(‘+’),退栈并输出 | #- | * |
23 | isp(‘-‘) > icp(‘+’),退栈并输出 | # | - | ||
24 | isp(‘#’) < icp(‘+’),进栈 | #+ | |||
25 | g | 操作数 | 直接输出 | #+ | g |
26 | # | 操作符 | isp(‘+’) > icp(‘#’),退栈并输出 | # | |
27 | isp(‘#’) == icp(‘#’),退栈,结束 |
第四题
将中缀表达式转换后缀表达式的算法思想如下:
从左向右开始扫描中缀表达式;
遇到数字时,加入后缀表达式;
遇到运算符时:
a.若为‘(’,入栈;
b.若为‘)’,则一次把栈中的运算符加入后缀表达式中,直到出现‘(’,从栈中删除‘(’;
c.若为除括号外的其他运算符,当其优先级高于除‘(’意外的栈顶运算符时,直接入栈。否则从栈顶开始,一次弹出比当前处理的运算符优先级高和优先级相等的运算符,直到一个比它优先级低的或者遇到了一个左括号位置。
当扫描的中缀表达式结束时,栈中的所有运算符一次出栈加入后缀表达式。
待处理序列 | 栈 | 后缀表达式 | 当前扫描元素 | 动作 |
---|---|---|---|---|
a/b+(c*d-e*f)/g | a | a加入后缀表达式 | ||
/b+(c*d-e*f)/g | a | / | /入栈 | |
b+(c*d-e*f)/g | / | a | b | b加入后缀表达式 |
+(c*d-e*f)/g | / | ab | + | +优先级低于栈顶的/,弹出/ |
+(c*d-e*f)/g | ab/ | + | +入栈 | |
(c*d-e*f)/g | + | ab/ | ( | (入栈 |
c*d-e*f)/g | +( | ab/ | c | c加入后缀表达式 |
*d-e*f)/g | +( | ab/c | * | 栈顶为(,*入栈 |
d-e*f)/g | +(* | ab/c | d | d加入后缀表达式 |
-e*f)/g | +(* | ab/cd | - | -优先级低于栈顶的,弹出 |
-e*f)/g | +( | ab/cd* | - | 栈顶为(,-入栈 |
e*f)/g | +(- | ab/cd* | e | e加入后缀表达式 |
*f)/g | +(- | ab/cd*e | * | *优先级高于栈顶的-,*入栈 |
f)/g | +(-* | ab/cd*e | f | f加入后缀表达式 |
)/g | +(-* | ab/cd*ef | ) | 把栈中(之前的符号加入表达式 |
/g | + | ab/cd*ef*- | / | /优先级高于栈顶的+,/入栈 |
g | +/ | ab/cd*ef*- | g | g加入后缀表达式 |
+/ | ab/cd*ef*-g | 扫描完毕,运算符一次退栈加入表达式 | ||
ab/cd*ef*-g/+ | 完成 |
由此可知,当扫描到f的时候,栈中的元素一次是+(-*
,选B。
再次再给出中缀表达式转换为前缀或后缀表达式的手工做法,以上面给出的中缀表达式为例:
第一步:按照运算符的优先级对所有的运算单位加括号
式子变成了:((a/b)+(((c*d)-(e*f)/g))
第二部:转换为前缀或后缀表达式。
前缀:把运算符号移动到对应的括号前面,则变成了:+(/(ab)/(-(*(cd)*(ef))g))
把括号去掉:+/ab/-*cd*efg
前缀式子出现
后缀:把运算符移动到对应的括号 后面,则变成了:((ab)/(((cd)*(ef)*)-g/)+
把括号去掉:ab/cd*ef*-g/+
后缀式子出现
当题目要求直接求前缀或后缀表达式时,这种方法会比上一中快捷的多。