赞
踩
一、什么是中缀表达式
二、什么是后缀表达式
三、后缀转中缀具体思路
四、代码实现
中缀表达式就是我们常用的算术表达方式,例如(12+34)*5,运算符在两个数的中间,但是对于中缀表达式来说括号和加减乘除使得问题对于计算机非常复杂,为了有效的处理他们,波兰逻辑学家想到了一种不需要括号的后缀表达式,我们称之为逆波兰。
后缀表达式也称逆波兰式或逆波兰记法,它通过中缀表达式转换而来,没有括号,只有数字和运算符,运算符总在要计算的数字的后面,之所以叫后缀表达式 是因为所有的运算符号都要在数字后面出现才行。举个例子来说,假如中缀表达式是:(12+34)*5那么转换为后缀表达式就是:12 34 + 5 *
看到这里,你可能蒙圈了,我们先把中缀表达式计算出来,结果是230。
此时此刻你一定想问,如何计算?其实很简单:
每次从左往右找到第一个运算符的位置,然后拿到前面两个位置的元素,跟这个运算符进行+-*/ 运算,运算完将运算符和这两个元素删掉,再将新算出来的元素添加到运算符前面的位置,每次都这样计算,当后缀表达式为空时,就可以得到最终的那个结果。
看到这里,你应该顿悟了吧,如果还不明白,后面我会给出代码,相信你会明白的。
接下来是思路:
第一步:定义两个栈,一个用来存储后缀表达式栈,一个用来存储中间的运算符栈。
第二步:写个循环,从左往右遍历中缀表达式。
第三步:在循环中处理数字和运算符即可
怎么处理呢?接下来就为大家讲解
如果遇到数字,代表他是要运算的值,直接入后缀表达式栈
如果遇到了运算符,可以分情况讨论,有以下情况
当前栈为空,那就代表是第一个运算符,入栈即可
当前栈不为空,当前运算符大于栈顶运算符,入栈即可,如果小于或等于当前运算符,直接将运算符栈弹至后缀表达式栈
遇到括号,也要分情况讨论,有以下情况
左括号,直接入栈即可
右括号,弹出运算符直至左括号为止(实际上就是把这个括号包含的所有运算符弹出)
还要注意一点:如果运算符当前栈顶是'(',那么下一个运算符无论是什么都要入栈
表达式遍历完后,把运算符栈剩下的弹至后缀表达式栈即可
- /*
- 中缀表达式转为后缀表达式具体思路:
- 1.定义两个栈,一个栈用来存储后缀表达式,一个栈用来存储中间的运算符
- (括号,+,-,/,*这些)
- 2.如果遇到数字,直接入后缀表达式栈
- 3.如果遇到运算符了,分情况讨论:
- 第一种:括号,如果是左括号,直接入栈,如果是右括号,把栈顶的运算符
- 给到后缀表达式栈中即可
- 第二种:+,-,*,/,这些,如果遇到运算符优先级大于栈顶的运算符,直接入
- 栈,如果遇到不大于栈顶的优先级的运算符,直接出栈,然后再把当前运算
- 符入栈即可(tips:注意如果是运算符优先级相同,把栈顶运算符出栈即可)
- 4.重复操作即可
- */
- #include <iostream>
- #include <stack>
- #include <vector>
- #include <string>
- #include <algorithm>
- typedef double d;
- using namespace std;
- enum Operator //运算符优先级
- {
- //左括号 右括号 加 减 乘 除
- left_bracket=2,right_bracket=0,Add=0, Minus=0, Multiply=1,Div=1
- };
- int Get_Operator_size(char cc){ //根据符号返回对应的运算符优先级
- switch (cc) {
- case '+': return Add;
- case '-': return Minus;
- case '*':return Multiply;
- case '/':return Div;
- case '(':return left_bracket;
- case ')':return right_bracket;
- default: return -1;
- }
- }
- struct expression{ //后缀表达式数据
- string str; //运算符或者要运算的数字
- expression(string str):str(str){}
- expression(){}
- };
- class Slove_expression{
- public:
- Slove_expression(){}
- Slove_expression(string Expree):Expree(Expree){}
- inline void Set_Expression(string Expree) { this->Expree = Expree;}
- vector<expression> Get_Front_expression() {
- int p = 0;
- string temp;
- expression Next;
- while (p<Expree.size()) {
- if(Expree[p]>='0' && Expree[p]<='9')
- temp.push_back(Expree[p]); //保存数据
- if ((p>=1 && Get_Operator_size(Expree[p])!=-1 && Expree[p-1]>= '0'
- && Expree[p - 1] <= '9')
- || p+1==Expree.size()) { //处理最后一个整数式子
- //遇到运算符了 并且前面是数字 让数字入栈
- Next.str = temp;
- Stack.push(Next); //如果是参与运算的数字 直接入栈
- temp.erase(temp.begin(),temp.end()); //将里面的数据删掉 防止重复
- }
- if (Get_Operator_size(Expree[p])!=-1 && (operation.empty() ||
- Get_Operator_size(Expree[p])>Get_Operator_size(operation.top().str[0])
- || operation.top().str[0]=='('))
- //如果运算符栈为空 直接将运算符入栈 或者运算符优先级大于顶栈运算符 入栈即可
- {
- //cout << Expree.substr(p, 1) << endl;
- Next.str = Expree.substr(p,1); //将运算符切割出来
- operation.push(Next); //运算符入栈
- }
- else if(Get_Operator_size(Expree[p])!=-1){ //运算符优先级一样 或者走到)运算符了
- if (Expree[p] == ')') //右括号处理方式
- {
- while(operation.top().str[0]!='('){
- Stack.push(operation.top());
- operation.pop();
- }
- operation.pop();
- }
- else { //非右括号
- Stack.push(operation.top()); //将运算符栈顶出栈
- operation.pop();
- Next.str = Expree.substr(p, 1);
- operation.push(Next);
- }
- }
- p++;
- }
- while (!operation.empty()){ //将剩下的运算符入栈
- Stack.push(operation.top());
- operation.pop();
- }
- vector<expression> arr;
- while (!Stack.empty()){
- expression curr = Stack.top();
- arr.insert(arr.begin(),curr);
- Stack.pop();
- //cout << curr.str << '\t';
- }
- //cout << endl;
- return arr;
- }
-
- private:
- stack<expression> Stack; //后缀表达式栈
- stack<expression> operation; //运算符栈
- string Expree; //表达式
- };
- class Value{ //通过后缀表达式计算出具体的值
- public:
- Value(){}
- Value(vector<expression> arr) :arr(arr){}
- inline void Set_Value_Arr(vector<expression> arr) { this->arr = arr; }
- d Two_Number_Value(d left,char cc,d right){
- switch (cc) {
- case '+': return left + right;
- case '-':return left - right;
- case '/':return left / right;
- case '*':return left * right;
- default:return -1;
- }
- }
- d Get_Value(){
- int p = 0;
- d two_Number;
- //加一个数据防止出现下标问题
- arr.push_back(expression(string("#")));
- while (1) {
- if (Get_Operator_size(arr[p].str[0]) != -1) { //找到运算符了
- two_Number = Two_Number_Value(stod(arr[p - 2].str), arr[p].str[0],
- stod(arr[p - 1].str));
- //cout << two_Number << endl;
- arr.erase(arr.begin()+p-2,arr.begin()+p+1);
- //cout << arr.size() << endl;
- if (arr.size()==1 && (*(arr.begin())).str[0] == '#')
- break;
- arr.insert(arr.begin()+p-2, expression(to_string(two_Number)));
- p -= 2;
- }
- p++;
- }
- return two_Number;
- }
- private:
- vector<expression> arr;
- };
- signed main() {
- string str;
- Slove_expression* solve = new Slove_expression;
- Value* value = new Value;
- while (1) {
- cout << "请输入表达式:";
- cin >> str;
- solve->Set_Expression(str);
- vector<expression> arr = solve->Get_Front_expression();
- value->Set_Value_Arr(arr);
- cout << "reslt:"<<value->Get_Value();
- cout << endl;
- }
- return 0;
-
- }
总结:中缀表达式转后缀表达式实际上就是栈的运用,如果你不了解栈,建议了解完再来看本篇文章。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。