一.前言:
逆波兰表示法 ( Reverse Polish notation , RPN ,或 逆波兰记法 ),是一种是由 波兰 数学家 扬·武卡谢维奇 1920年引入的数学表达式形式,在逆波兰记法中,所有 操作符 置于 操作数 的后面,因此也被称为 后缀表示法 (也称后缀表达式)。而我们平常用的a+b叫做中缀表达式,转换成后缀表达式为ab+(其实还有一个波兰式,也就作前缀表达式+ab),为什么要这么转换呢?虽然我们人脑非常喜欢这种显而易见的中缀表达式计算,但是计算机算觉得这非常的难计算(主要是堆栈的实现会变的比中缀表达式更简单),因此就有了波兰表达式和逆波兰表达式。
二.问题分析:
那我们如和将中缀表达式转成后缀表达式呢?总所周知,在中缀表达式中我们的操作符+-优先级最低,*/优先级第二,而()优先级最高。但是在逆波兰式的转换过程中这个优先级有一些变化,乘除的优先级会看成比加减的优先级更低,括号优先级依旧是最高,因此我们可以有定义+-优先级为2,()优先级为1,*/优先级为3。因此我们就解决掉了优先级的问题。
其他规则
1.如果碰到左括号,则直接入栈。
2.如果碰到优先级高于栈顶的,则依次出栈,直到栈顶为空或者栈顶的优先级高于碰到的操作符,然后再把操作符加入栈区即可
3.如果中缀表达式遍历完成后,栈区还剩余操作符,则直接把剩余操作符从栈顶依次加入逆波兰式
4.如果碰到右括号,则把括号和右括号之间的操作符加入逆波兰式,左括号和右括号出栈
接下来我们看看具体怎么转换吧!
首先,我们给出一个计算样例来解释计算过程,中缀表达式如下:1+2*(3+4)/5
我们给出一个栈区用来存操作符,用一个字符串来存储逆波兰式
碰到1,直接加入逆波兰式
stack(代表栈区):NULL
bolan(代表逆波兰式):1
碰到‘+’,因为栈区此时为空,故直接加入栈区
stack(代表栈区):+
bolan(代表逆波兰式):1
碰到2,直接加入逆波兰式
stack(代表栈区):NULL
bolan(代表逆波兰式):1,2
碰到‘*’,因为*的优先级为2,最低,故不需要弹出+号,因此直接入栈\
stack(代表栈区):+,*
bolan(代表逆波兰式):1,2
碰到‘(’,因为左括号需要续’)’相匹配,故直接入栈
stack(代表栈区):+,*,(
bolan(代表逆波兰式):1,2
碰到数字3,直接加入逆波兰式
stack(代表栈区):+,*,(
bolan(代表逆波兰式):1,2,3
碰到‘+’,因为+优先级低于括号,因此直接入栈
stack(代表栈区):+,*,(,+
bolan(代表逆波兰式):1,2,3
碰到数字4,直接加入逆波兰式
stack(代表栈区):+,*,(,+
bolan(代表逆波兰式):1,2,3,4
碰到‘(‘,把左括号之前的全部加入逆波兰式
stack(代表栈区):+,*
bolan(代表逆波兰式):1,2,3,4,+
碰到’/’,把栈顶优先级不高于’/’的全部加入逆波兰式,再把自己加入栈区
stack(代表栈区):+,/
bolan(代表逆波兰式):1,2,3,4,+,*
碰到数字5,直接加入波兰式
stack(代表栈区):+,/
bolan(代表逆波兰式):1,2,3,4,+,*,5
字符串遍历结束,把栈区剩下的全部加入逆波兰式
stack(代表栈区):NULL
bolan(代表逆波兰式):1,2,3,4,+,*,5,/,+
三.代码实现:
1 #include "bits/stdc++.h" 2 using namespace std; 3 int jdgCode(char flag)//定于操作符运算 4 { 5 if(flag == '+') 6 return 1; 7 if(flag == '-') 8 return 2; 9 if(flag == '*') 10 return 3; 11 if(flag == '/') 12 return 4; 13 } 14 double Compute(string cpu) 15 { 16 stack <double> ans; 17 for(auto iter = cpu.begin();iter != cpu.end();iter++){ 18 if(*iter >= '0' && *iter <= '9') 19 ans.push(*iter - '0'); 20 else { 21 double r1,r2; 22 r1 = ans.top(); 23 ans.pop(); 24 r2 = ans.top(); 25 ans.pop(); 26 switch(jdgCode(*iter)){ 27 case 1: ans.push(r2 + r1);break; 28 case 2: ans.push(r2 - r1);break; 29 case 3: ans.push(r2 * r1);break; 30 case 4: ans.push(r2 / r1);break; 31 } 32 } 33 } 34 return ans.top(); 35 } 36 int prio(char a) 37 { 38 if(a == '*' || a == '/') 39 return 2; 40 else if(a == '+' || a == '-') 41 return 1; 42 else 43 return 0;//左括号优先级 44 } 45 void Dispose(string& ms,string& as)//处理成后缀表达式 46 { 47 stack <char> ct;//定义一个ct容器存储运算符 48 for(auto iter = ms.begin();iter != ms.end();iter++){ 49 if(*iter >= '0' && *iter <= '9')//如果是数字,直接入栈 50 as += *iter; 51 else{ 52 if(ct.empty() || *iter == '(')//如果是空栈,或者是左括号,直接入栈 53 ct.push(*iter); 54 else if(*iter == ')'){ 55 while(ct.top() != '('){//把左括号和右括号里面的操作符出栈 56 as += ct.top(); 57 ct.pop(); 58 } 59 ct.pop();//弹出左括号 60 } 61 else{ 62 while(!ct.empty() && prio(*iter) <= prio(ct.top())){//把优先级低于当前操作符的操作符出栈 63 as += ct.top(); 64 ct.pop(); 65 } 66 ct.push(*iter);//把当前操作符入栈 67 } 68 } 69 } 70 while(!ct.empty()){//如果栈区还有操作符 71 as += ct.top(); 72 ct.pop(); 73 } 74 } 75 int main() 76 { 77 string ms;//中缀表达式 78 string as;//后缀表达式 79 cin >> ms; 80 Dispose(ms,as);//将中缀表达式处理为后缀表达式 81 cout << as << endl;//输出处理后的后缀表达式 82 cout << "Result:" << Compute(as) << endl;//输出后缀表达式计算结果 83 return 0; 84 }
本文来自博客园,作者:{scanner},转载请注明原文链接:{https://home.cnblogs.com/u/scannerkk/}
今天的文章逆波兰式分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/56900.html