中缀表达式转后缀表达式(1、2、3) 2021-03-26

简介: 中缀表达式转后缀表达式(1、2、3) 2021-03-26

中缀表达式是一个通用的算术或逻辑公式表示方法, 操作符是以中缀形式处于操作数的中间,是人们常用的算术表示方法

后缀表达式指的是不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)。

中缀表达式转后缀表达式     A+(B-C)*D+E/F  的转换为例

第一种:基于堆栈的算法

下面简述转换方法:

1、遇到操作数,直接输出。

2、如果不是操作数,分为以下几种情况

(1)如果是左括号'(',则入栈。(特别注意左括号'('入栈后优先级为最小。)

(2)如果操作符栈为空,则入栈。

(3)如果当前操作符优先级大于栈顶操作符,则入栈。

(4)如果当前操作符优先级小或等于栈顶操作符,则操作符栈出栈(且输出),直到当前操作符优先级大于栈顶操作符,或者操作符栈为空,或者遇到 左括号'('为止,入栈当前操作符。

(5)如果是右括号')',则操作符栈一直出栈(且输出),直到遇到 左括号'(',并出栈左括号'('。

(6)如果当前字符串读入完毕,且操作符栈非空,则操作符栈一直出栈(且输出),直到操作符栈为空。

1. //C语言 代码
2. #include <stdio.h>
3. #include <string.h>
4. typedef struct node{//建立栈模拟结构体 
5.  char s[310];int top;//s存储符号 top为栈顶指针 
6. }Stack;
7. int weight(char ch){//运算符优先级 flag确定'('来源   
8.  if(ch=='+'||ch=='-') return 1; 
9.  if(ch=='*'||ch=='/'||ch=='^') return 2;
10.   if(ch=='(') return 0;
11. }
12. void transform(char str[]){
13.   Stack a;//新建栈a 
14.   a.top=-1;//初始化栈指针 
15.   int i,f=0,m=strlen(str);
16.   for(i=0;i<m;i++){//遍历整个字符串 
17.     if(str[i]>='A'&&str[i]<='Z')//1.读取字符串是数字直接弹出 
18.       printf("%c",str[i]);
19.     else {
20.       if(a.top==-1||str[i]=='('){//2.读取是操作符  如栈为空 直接入栈 
21.         a.s[++a.top]=str[i];continue;
22.       }
23.       else if(str[i]==')'){//3.读取是操作符 是')'且栈不为空 弹出栈顶元素直到找到'('为止 
24.         while(a.top!=-1&&a.s[a.top]!='(') 
25.           printf("%c",a.s[a.top--]);
26.         --a.top;continue;//弹出'('
27.       }
28.       //4.读取是操作符 字符串字符大于栈顶字符的优先级 直接入栈 
29.       else if(weight(str[i])>weight(a.s[a.top])){
30.         a.s[++a.top]=str[i];continue;
31.       }
32.       //5.读取是操作符 栈不为空 且 字符串字符<=栈顶字符的优先级 
33.       //重复弹出栈定字符 直到 栈为空 或者 字符串字符>栈顶字符的优先级 或者碰到'('
34.       while(a.top!=-1&&weight(str[i])<=weight(a.s[a.top])&&a.top!='('){
35.         printf("%c",a.s[a.top]);--a.top;f=1;
36.       }
37.       if(f==1){//将新读取字符加入栈顶 
38.         a.s[++a.top]=str[i];f=0;
39.       } 
40.     }
41.   }
42.   //6.字符串读取结束,如果栈不为空重复弹出栈顶字符 直到栈空 
43.   while(a.top!=-1) printf("%c",a.s[a.top--]);
44. }
45. int main(int argc, char *argv[])
46. {
47.   char str[310];
48.   gets(str);
49.   transform(str);   
50.   return 0;
51. }
52. 
53. //输入:A+B*C+(D*E+F)*G
54. //输出:ABC*+DE*F+G*+
55. 
56. //输入:A+((B+C)*D)–E
57. //输出:ABC+D*+E-
58. 
59. //输入:A+(B-C)*D+E/F
60. //输出:ABC-D*+EF/+
61. 
62. //输入:A+(B+C)*(D^E+F*G)/(H)
63. //输出:ABC+DE^FG*+*H/+

第二种:括号法  A+B*C+(D*E+F)*G

1)先按照运算符的优先级对中缀表达式加括号,变成( ( A+(B*C) ) + ( ((D*E)+F) *G ) )

2)将运算符移到括号的后面,变成((A(BC)*)+(((DE)*F)+G)*)+

3)去掉括号,得到ABC*+DE*F+G*+

A+((B+C)*D)–E

((A+((B+C)*D))–E)

((A((BC)+D)*)+E)–

ABC+D*+E-

A+(B-C)*D+E/F

((A+((B-C)*D))+(E/F))

((A((BC)-D)*)+(EF)/)+

ABC-D*+EF/+

A+(B+C)*(D^E+F*G)/(H)

(A+((B+C)*((D^E)+(F*G))/(H)))

(A((BC)+((DE)^(FG)*)+*(H))/)+

ABC+DE^FG*+*H/+

第三种:利用语法树

步骤如下

1. 找到表达式中优先级最低的运算符作为树根(注意括号会提升内部的优先级),并将原表达式分解成左右两个表达式;

2. 分别对左右表达式做步骤:  左边生成的树为树根的左子树,右边生成的树为树根的右子树;

3.  重复步骤1,2, 直到分解的表达式里没有运算符(只剩下数字)为止;

1、将A+B*C+(D*E+F)*G式子转化为二叉树

2、通过后序遍历将其写出来,即可得到结果:ABC*+DE*F+G*+

在这里补充一点,如何将表达式变成二叉树:

表达式生成树的特点为:

   a. 叶子节点都是操作数;

   b. 非叶子节点都是运算符;

   c. 树根的运算符优先级低;

注意一点:在遇到像本式中a后面的+号和c后面的+的优先级问题,在正常计算时a后面的+会先使用所以他的优先级比c后面的+优先级高。所以能得到上面的二叉树。

例如:将A+((B+C)*E)-F式子转化为二叉树,通过后序遍历可得到结果:ABC+E*+F-

例如:将A+(B-C)*D+E/F式子转化为二叉树,通过后序遍历可得到结果:ABC-D*+EF/+

例如:将A+(B+C)*(D^E+F*G)/(H)式子转化为二叉树,通过后序遍历可得到结果:ABC+DE^FG*+*H/+

输入中缀表达式计算表达式的结果

【输入样例】1+(3+2)*(7^2+6*9)/(2)         【输出样例】258

1. //C++代码  注意测试点课能有 +-*/^()0~9 以外的字符 
2. #include <iostream>
3. #include <cstdio>
4. #include <cstring>
5. #include <string>
6. #include <stack>
7. #include <cmath>
8. #include <cstdlib>
9. #include <vector>
10. using namespace std;
11. int get_fast(string op)//运算符的优先级 
12. {
13.   int ans=-1;
14.   switch(op[0]){
15.     case '+':case '-': ans=1;break;
16.     case '*':case '/': ans=2;break;
17.     case '^': ans=3;break;  
18.   }
19.   return ans;
20. }
21. vector<string> scaner(string s)//将字符串解析到vector 
22. {
23.   vector<string> ans;
24.   string ops="+-*/^()";
25.   string t="";
26.   for(int i=0;i<s.size();i++){
27.     if(s[i]>='0'&&s[i]<='9') t+=s[i];
28.     else if(ops.find(s[i])!=string::npos) {//注意有特殊字符 
29.       if(t.size()>0)ans.push_back(t);
30.       t=s[i];
31.       ans.push_back(t);
32.       t="";
33.     }
34.   }
35.   if(t.size())ans.push_back(t);//将最后一个数字放入vector 
36.   //for(int i=0;i<ans.size();i++)cout<<ans[i];
37.   //cout<<endl; 
38.   return ans;
39. }
40. vector<string> infix_suffix(vector<string> exp)//中缀表达式转后缀表达式 
41. {
42.   vector<string> ans;
43.   stack<string> st;
44.   string ops="+-*/^";
45.   for(int i=0;i<exp.size();i++){
46.     if(exp[i]=="(")//1、"("直接进栈 
47.       st.push(exp[i]);
48.     else if(exp[i]==")"){//2、")"在找到"("之前连续出栈运算符  
49.       while(st.top()!="("){
50.         ans.push_back(st.top());
51.         st.pop();
52.       }
53.       st.pop();//弹出"("  
54.     }
55.     else if(ops.find(exp[i])!=string::npos){//3、确定是运算符 
56.       while(st.size()&&get_fast(exp[i])<=get_fast(st.top())){
57.         ans.push_back(st.top());
58.         st.pop();//如果栈顶的运算符优先级大于等于当前运算符 栈顶的运算符被连续弹出 
59.       }
60.       st.push(exp[i]);//当前运算符进栈 
61.     }
62.     else ans.push_back(exp[i]);//4、数字直接进栈 
63. 
64.   }
65.   while(st.size()) {ans.push_back(st.top());st.pop();}//5、栈内剩余运算符被连续弹出 
66.   //for(int i=0;i<ans.size();i++)cout<<ans[i]<<endl;
67.   return ans;
68. }
69. int suffix_calc(vector<string> exp)//后缀表达式计算结果 
70. {
71.   stack<int> num;
72.   string ops="+-*/^";
73.   for(int i=0;i<exp.size();i++){
74.     if(ops.find(exp[i])!=string::npos){//是运算符,弹出两个数字运算并入栈 
75.       int a=num.top();num.pop();
76.       int b=num.top();num.pop();
77.       if(exp[i]=="+") num.push(b+a);
78.       else if(exp[i]=="-") num.push(b-a);
79.       else if(exp[i]=="*") num.push(b*a);
80.       else if(exp[i]=="/") num.push(b/a);
81.       else if(exp[i]=="^") num.push(pow(b*1.0,a));
82.     }
83.     else {//字符串是数字,转换成整数并入栈 
84.       num.push(atoi(exp[i].c_str()));
85.     }
86.   }
87.   //cout<<num.top()<<endl;
88.   return num.top();
89. }
90. int main(int argc, char *argv[])
91. {
92.   string st;
93.   getline(cin,st);//读取字符串 
94.   vector<string> vs=scaner(st);//将字符串解析到vector 
95.   vs=infix_suffix(vs);//中缀表达式转后缀表达式 
96.   cout<<suffix_calc(vs)<<endl;//输出后缀表达式计算结果 
97.   return 0;
98. }

 

相关文章
|
19天前
|
存储 算法 C语言
C语言编程—中缀表达式转换为后缀表达式
1.创建栈 2.从左向右顺序获取中缀表达式 a.数字直接输出 b.运算符 情况一:遇到左括号直接入栈,遇到右括号将栈中左括号之后入栈的运算符全部弹栈输出,同时左括号出栈但是不输出。 情况二:遇到乘号和除号直接入栈,直到遇到优先级比它更低的运算符,依次弹栈。 情况三:遇到加号和减号,如果此时栈空,则直接入栈,否则,将栈中优先级高的运算符依次弹栈(注意:加号和减号属于同一个优先级,所以也依次弹栈)直到栈空或则遇到左括号为止,停止弹栈。(因为左括号要匹配右括号时才弹出)。 情况四:获取完后,将栈中剩余的运算符号依次弹栈输出 例:将:2*(9+6/3-5)+4转化为后缀表达式 2 9
45 0
|
9月前
【逆波兰表达式求值】
【逆波兰表达式求值】
|
7天前
|
索引
【力扣刷题】数组实现栈、后缀表达式(逆波兰表达式)求值、中缀表达式转换为后缀表达式(无括号&&有括号)
【力扣刷题】数组实现栈、后缀表达式(逆波兰表达式)求值、中缀表达式转换为后缀表达式(无括号&&有括号)
13 0
|
19天前
彻底大悟!逆波兰表达式求值(150)
彻底大悟!逆波兰表达式求值(150)
|
10月前
中缀表达式转后缀表达式(逆波兰式)
中缀表达式转后缀表达式(逆波兰式)
|
11月前
1198:逆波兰表达式
1198:逆波兰表达式
|
12月前
后缀表达式
后缀表达式
75 0
|
12月前
|
存储
中缀表达式转化为后缀表达式
中缀表达式转化为后缀表达式
7-323 逆波兰表达式
7-323 逆波兰表达式
40 0
leetcode150–逆波兰表达式求值(栈/后缀表达式)
leetcode150–逆波兰表达式求值(栈/后缀表达式)