刁肥宅详解中缀表达式求值问题:C++实现顺序/链栈解决
Posted 25th-engineer
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了刁肥宅详解中缀表达式求值问题:C++实现顺序/链栈解决相关的知识,希望对你有一定的参考价值。
1. 表达式的种类
如何将表达式翻译成能够正确求值的指令序列,是语言处理程序要解决的基本问题,作为栈的应用事例,下面介绍表达式的求值过程。 任何一个表达式都是由操作数(亦称运算对象)、操作符(亦称运算符)和分界符组成的。通常,算术表达式有3种表示: ①中缀(infix)表示:<操作数><操作符><操作数>,如A+B。 ②前缀(prefix)表示: <操作符><操作数><操作数>,如+AB。 ③后缀(postfix)表示: <操作数><操作数><操作符>,如AB+。
2. 求解算法
在中缀表达式中操作符的优先级和括号使得求值过程复杂化,把它转换成后缀表达式,可以简化求值过程。但是,老师使用的PPT上的示例显然是直接对中缀表达式进行求值,并未进行转换。因此我也采用“直接求值法”。为了实现对中缀表达式的求值,需要考虑各操作符的优先级,参见表1。
操作符ch | # | ( | *、/、% | +、- | ) |
isp | 0 | 1 | 5 | 3 | 6 |
icp | 0 | 6 | 4 | 2 | 1 |
表1 各个运算符的优先级
表中的isp叫做栈内优先级(in stack priority),icp叫做栈外优先级(in coming priority)。为什么要如此设置呢?这是因为某一操作符按照算术四则运算有一个优先级,这是icp。一旦它进入操作符栈,它的优先级要提高,以体现优先级相同的操作符先来的先做,就是说,在表达式中运算优先级相同的必须自左向右运算,这就是栈内优先级isp。
从上表可以看到,左括号“(”的栈外优先数最高,它一来到立即进栈,但当它进入栈中后,其栈内优先数变得极低,以便括号内的其他操作符进栈。除它之外,其他操作符进入栈中后优先数都升1,这样可以体现中缀表示中相同优先级的操作符自左向右计算的要求,让位于栈顶的操作符先退栈输出。操作符优先数相等的情况只出现在“(”与栈内“)”括号配对或栈底的“#”号与表达式输入最后的“#”号配对时。前者将连续推出位于栈顶的操作符,直到遇到“)”为止。然后将“(”退栈以对消括号,后者将结束算法。
扫描中缀表达式,并求值的算法描述如下:
1)操作符栈初始化,将结束符“#”进栈;操作数栈初始化。然后读入中缀表达式字符流中的首字符 ch。
2)重复执行以下步骤,直到 ch=“#”,同时栈顶的操作符也是“#”,停止循环。
①若 ch 是操作数,将压入操作数栈,读入下一个字符 ch。
②若 ch 是操作符,比较ch的优先级 icp 和操作符栈当前栈顶的操作符 op 的优先级 isp:
? 若 icp(ch)> isp(op),令ch进栈,读入下一个字符ch。
? 若 icp(ch)≤ isp(op),退出运算数栈的两个元素a和b计算:a op b,将计算结果压入运算数栈中。
? 若 ch = “)”或 op = “(”,退出运算符栈的栈顶元素,读入下一字符ch。
3)算法结束,运算数栈的栈顶元素即为所求中缀表达式的结果。
以上算法是我结合在资料上看到的关于中缀表达式转换为后缀表达式的算法,自己琢磨出来的。算法的正确性有待证明,但实现在计算几个样例时,结果正误均有。具体结果将在第四部分展示。
另外,我在博客和《算法导论》上都看到所谓“双栈算术表达式求值算法”的介绍与大概思路:
双栈算术表达式求值算法是由E.W.Dijkstra在上个世纪60年代发明的一个很简单的算法,用两个栈【一个用来保存运算符、一个用来保存操作数】来完成对一个表达式的运算。其实整个算法思路很简单:
? 无视左括号
? 将操作数压入操作数栈
? 将运算符压入运算符栈
? 在遇到右括号的时候,从运算符栈中弹出一个运算符,再从操作数栈中弹出所需的操作数,并且将运算结果压入操作数栈中
---------------------
作者:erzhanchen
来源:CSDN
原文:https://blog.csdn.net/erzhanchen/article/details/57421267
版权声明:本文为博主原创文章,转载请附上博文链接!
为了表示对原作者的尊重,我保留了“犯罪痕迹”。
3. 核心代码
在正式贴出核心代码(完整代码将写在下一篇博客)前先进行一些必要说明: ①从右向左扫描表达式字符串; ②C类型的字符串开始下标是0,字符串的最后一个元素是“ ”;
D | a | t | a | ‘ ‘ | S | t | r | u | c | t | u | r | e | ‘ ‘ |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
③假设“1”、“2”、“3”、“4”、“5”这五个数字组成一个十进制的整数,从左到右依次是万位数、千位数、百位数、十位数、个位数,那么计算这个整数的表达式就是下面这样的: 1×104 +2×103+3×102+4×101+5×100=12345
1 void SeqStack::calculate( char* Str )///C类型字符串表达式为参数传入方法中
2 {
3 charSeqStack css1;///css1 用作操作符栈
4 char ch1;///访问操作符栈栈顶元素时,保存栈顶元素
5 int i = 0;///用来保存当前扫描的表达式位置
6 double a, b;///用来保存临时运算时调用对象栈栈顶的前两个元素
7
8 int cnt = 0;///记录字符串中数字连续时的位数,即计算 10 的 n 次方时幂的指数
9 ///比方说:在读入整数156时,读“1”这个字符之前读了两个数字“5”、“6”,那么读1的时候,这个1就代表100的意思。
10 int temp = 0;///保存扫描到的数值
11
12 while ( Str[i] != ‘