栈的应用举例
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
栈的应用举例(栈与表达式)
[引言]
处理表达式是高级语言的编绎中的一个基本问题。它的实现是栈的一个重要应用,通过对处理表达式的讨论,可以帮助我们进一步了解栈的性能。
[内容讲授]
栈在计算机科学领域有着广泛的应用。比如在编译和运行计算机程序的过程中,就需要用栈进行语法检查(如检查begin和end、“(”和“)”等是否匹配)、计算表达式的值、实现过程和函数的递归调用等。下面举例说明栈在这些方面的应用。
例1、假设一个表达式有英文字母(小写)、运算符(+,—,*,/)和左右小(圆)括号构成,以“@”作为表达式的结束符。请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回“YES”;否则返回“NO”。表达式长度小于255,左圆括号少于20个。
分析:假设输入的字符串存储在c中(var c:string[255])。
我们可以定义一个栈:var s:array[1..maxn] of char;top:integer;
用它来存放表达式中从左往右的左圆括号。
算法的思路为:顺序(从左往右)扫描表达式的每个字符c[i],若是“(”,则让它进栈;若遇到的是“)”,则让栈顶元素出栈;当栈发生下溢或当表达式处理完毕而栈非空时,表示不匹配,返回“YES”,否则表示匹配返回“NO”。
程序代码如下:
var c:string;
function doit(c:string):boolean;
var s:array[1..20] of char;
top,i:integer;
ch:char;
begin
top:=0;
i:=1;ch:=c[i];
while ch<>'@' do
begin
if (ch='(') or (ch=')') then
case ch of
'(':begin top:=top+1;s[top]:='(' end;
')':if top>0 then top:=top-1
else begin doit:=false;exit end;
end;
i:=i+1;ch:=c[i];
end;
if top=0 then doit:=true
else doit:=false;
end;
begin
assign(input,'in.txt');
reset(input);
readln(c);
writeln(doit(c));
close(input);
end.
[补充]关于表达式的三种表示法。
1、中缀表达式:a+b
2、后缀表达式:ab+
3、前缀表达式:+ab
4、中缀转后缀的方法及举例转换:
一般方法:把每个运算符移到它的两个运算数后面,每个运算数后多加上一个空格
(为了分隔各个运算数),然后去掉所有括号即可。如:
3/5+6——————————3□5□/□6□+ {□表示空格,下同}
16-9*(4+3)——————19□9□4□3□+*-
2*(x+y)/(1-x)———————2□x□y□+*1□x□-/
(25+x)*(a*(a+b)+b)————25□x□+a□a□b□+*b□+*
另外一种手工方法:可以用后面讲到的二叉表达式树结合先序、中序和后序遍历。
5、中缀表达式的运算规则比较多,包括优先级、左右次序和括号;尤其是括号可以改
变优先顺序,这就只能在计算的每一步,用肉眼去扫描、观察和比较整个表达式中
谁的优先级高,就先计算那部分。但用计算机去做就很麻烦,而且效率不高。所以,计算机科学中是把中缀表达式先转换成后缀表达式,在利用计算机来计算后缀表达
式的值。后缀表达式又称“逆波兰式”,在后缀表达式中,不存在括号,也不存在
优先级的差别,计算过程完全按照运算符出现的先后顺序进行,整个计算过程仅需
一遍扫描即可完成。
6、两个任务:
(1)把中缀表达式转换成后缀表达式;
(2)求后缀表达式的值;
例2、输入一个中缀表达式,编程输出其后缀表达式,要求输出的后缀表达式的运算次序与输入的中缀表达式的运算次序相一致。为简单起见,假设输入的中缀表达式由+(加)、-(减)、×(乘)、/(除)四个运算符号以及左右圆括号和大写英文字母组成,其中算术运算符遵守先乘除后加减的运算规则。假设输入的中缀表达式长度不超过80个字符,且都是正确的,即没有语法错误,并且凡出现括号其内部一定有表达式,即内部至少有一个运算符号。以下是一个运行实例。
输入:X+A*(Y-B)-Z/F
输出:XAYB-*+ZF/-
[算法设计]
设置两个栈:操作数栈(ovs )和运算符栈(ops ),用来分别存放表达式中的操作数和运算符。开始时操作数栈为空,运算符栈中放入一个特殊的标志运算符号#号,并在表达式的末尾加上一个#号,并规定#号的优先级最低,然后从左向右扫描表达式,凡遇操作数便一律进栈;若遇运算符,则判断其优先级是否大于运算符栈栈顶元素的优先级。若小,则栈顶运算符退栈,并从操作数栈中弹出两个操作数(操作数为后缀表达式)进行后缀变换处理,处理结果进操作数栈,重复刚才的比较,直到栈顶运算符的优先级大于等于当前运算符的优先级,此时,若当前运算符的优先级大于栈顶运算符的优先级,则当前运算符进栈,继续扫描;若当前运算符的优先级等于栈顶运算符的优先级,则弹出栈顶运算符,继续扫描。扫描完该表达式后运算符栈为空,操作数栈中只有一个元素,该元素就是所要求的后缀表达式。
以下程序中的数组f 用来存放运算符之间的优先级关系,1(>)表示前面的运算符优先于后面的运算符,-1(<)表示后面的
运算符优先于前面的运算符,0(=)表示前面的运算符的优先级与后面的运算符相同,2(ERROR)表示这两个运算符如果在扫描中相遇的话,意味着该表达式是错误的。需要补充的是:左括号的优先级是最高的,而里层的左括号比外层的左括号更优先,右括号的优先级是除#号以外最低的,但左括号和右括号的优先级则是相等的,这样定义的目的是为了消去括号。以上规律列表如下: + - * / ( ) # + > > < < < > > - > > < < < > > * > > > > < > > / > > > > < > > ( < < < < < = ERROR ) > > > > ERROR > > # <
<
<
<
<
ERROR
=
P2
P1