C++表达式求值与转换(前缀、中缀、后缀)

一、前言

最近复习到数据结构的栈和队列的应用部分,学习了一下王道视频里表达式求值部分的思路,特地写了下代码跟大家分享,仅供学习参考。若有错误的地方,请多指教!😄😄😄

二、目录

1、中缀表达式转前缀表达式
2、中缀表达式转后缀表达式
3、前缀表达式求值
4、后缀表达式求值
5、中缀表达式求值

三、正文

1、中缀表达式转前缀表达式

建议先看中缀表达式转后缀表达式,比较好理解一些。

思路

1、从右往左扫描中缀表达式,直到最后一个元素为止:

  • 如果遇到操作数。则直接加入前缀表达式。
  • 如果遇到运算符。则比较当前运算符和栈顶符号的优先级。
    • 如果当前运算符的优先级大于栈顶符号的优先级,则直接将该运算符压入栈中;
    • 否则,依次弹出栈中所有优先级大于等于当前运算符的所有运算符,并加入到前缀表达式。最后把当前运算符压入栈中。
  • 如果遇到界限符。
    • 遇到右括号“)”,则直接将右括号压入栈中;
    • 遇到左括号“(”,则依次弹出栈内运算符并加入前缀表达式,直到弹出右括号“)”为止。注意“)”不加入前缀表达式。

2、最后,将栈中剩余的运算符依次弹出,并加入到前缀表达式。注意此时得到的是前缀表达式的逆序,我们需要将结果倒序一下,大功告成!😁😁😁
注意:括号的优先级应该设为最低噢!

代码
//规定优先级
int level(char s){
    if(s=='+' || s=='-')
        return 1;
    else if (s=='*'||s=='/')
        return 2;
        //设括号优先级为0
    else return 0;
}

//中缀表达式转前缀表达式
char* infix_to_prefix(char *str){
    //用栈结构,将字符串倒序,以符合“从右往左”原则。
    stack<char> s;
    int i=0;
    while(str[i]!='\0'){
        s.push(str[i]);
        ++i;
    }

    //定义一个栈来保存结果;
    stack<char> result;
    //定义一个栈来作为符号栈
    stack<char> symbol_stack;
    while(!s.empty()){
        char temp=s.top();
        s.pop();

        //--------------数字处理------------------
        if(temp>='0'&&temp<='9'){
            result.push(temp);
        }

        //--------------运算符处理-----------------
        else if(temp=='+'||temp=='-'||temp=='*'||temp=='/'){
            //如果符号栈为空 或者 扫描到的 运算符的 优先级 > 符号栈的 栈顶符号的 优先级
            if(symbol_stack.empty()||level(temp)> level(symbol_stack.top())){
                symbol_stack.push(temp);
            }
            //如果扫描到的 运算符的 优先级 <= 符号栈的 栈顶符号的 优先级
            else if(level(temp)<= level(symbol_stack.top())){
                //弹出 优先级 高于或等于 当前运算符优先级的 所有符号
                while(!symbol_stack.empty()&&level(symbol_stack.top())>= level(temp)){//先判空再用top()不然会报错!
                    result.push(symbol_stack.top());
                    symbol_stack.pop();
                }
                //将当前符号压入栈中
                symbol_stack.push(temp);
            }
        }

        //----------------界限符处理--------------------
        else{
            //遇到右括号,直接进栈
            if(temp==')'){
                symbol_stack.push(temp);
            }
            //遇到左括号,依次弹出符号栈内运算符,知道遇到右括号
            else{
                while (symbol_stack.top()!=')'){
                    result.push(symbol_stack.top());
                    symbol_stack.pop();
                }
                symbol_stack.pop();//将')'也出栈
            }
        }
    }

    //将符号栈内剩余符号全部取出
    while(!symbol_stack.empty()){
        result.push(symbol_stack.top());
        symbol_stack.pop();
    }

    //将结果赋值到字符串数组
    int j=0;
    char *res=new char[20];
    while(!result.empty()){
        res[j++]=result.top();
        result.pop();
    }
    
    //加入字符串结束字符'\0'
    res[j]='\0';
    return res;
}
结果

在这里插入图片描述

2、中缀表达式转后缀表达式

思路

1、从左往右扫描中缀表达式,直到最后一个元素为止:

  • 如果遇到操作数。则直接加入后缀表达式。
  • 如果遇到运算符。则比较当前运算符和栈顶符号的优先级。
    • 如果当前运算符的优先级大于栈顶符号的优先级,则直接将该运算符压入栈中;
    • 否则,依次弹出栈中所有优先级大于等于当前运算符的所有运算符,并加入到后缀表达式。最后把当前运算符压入栈中。
  • 如果遇到界限符。
    • 遇到左括号“(”,则直接将左括号压入栈中;
    • 遇到右括号“)”,则依次弹出栈内运算符并加入后缀表达式,直到弹出左括号“(”为止。注意“(”不加入后缀表达式。

2、最后,将栈中剩余的运算符依次弹出,并加入到后缀表达式。大功告成!😁😁😁
注意:括号的优先级应该设为最低噢!

代码
//规定优先级
int level(char s){
    if(s=='+' || s=='-')
        return 1;
    else if (s=='*'||s=='/')
        return 2;
    //设括号优先级为0
    else return 0;
}

//中缀表达式转后缀表达式,返回值为字符串
char* infix_to_postfix(char* str){
    char*res=new char [20];//用来存放结果
    int index=0;
    stack<char> stack;
    for(int i=0;str[i]!='\0';++i){
        //--------------数字处理---------------------------
        if('0'<=str[i]&&str[i]<='9'){
            res[index++]=str[i];
        }

        //--------------运算符处理-------------------------
        else if (str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'){
            //扫描到的 符号的 优先级 >  栈顶符号的 优先级 或者 符号栈为空,直接进栈
            if(stack.empty() ||level(stack.top())< level(str[i]))
                stack.push(str[i]);
            //扫描到的符号的优先级 <= 栈顶符号的 优先级 
            else{
                //弹出栈中优先级高于或等于当前运算符的 所有 运算符
                while(!stack.empty()&&level(stack.top())>= level(str[i])){ //先判空再用stack.top()不然会报错!
                    res[index++]=stack.top();
                    stack.pop();
                }
                stack.push(str[i]); //最后把扫描到的字符压入栈中
            }
        }

        //---------------界限符处理----------------------
        else{
            if(str[i]=='(') //遇到左括号'(',直接进栈
                stack.push(str[i]);
            else{           //遇到右括号')'依次弹出栈内运算符,直到遇到左括号'('
                while(stack.top()!='('){
                    res[index++]=stack.top();
                    stack.pop();
                }
                stack.pop();//左括号也出栈
            }
        }
    }

    //将栈中所有剩余字符送入表达式
    while(!stack.empty()){
        res[index++]=stack.top();
        stack.pop();
    }
    
    //加入字符串结束字符'\0'
    res[index]='\0';
    return res;
}
结果

在这里插入图片描述

3、前缀表达式求值

思路

1、从右往左描表达式中的每个元素,直到最后一个元素为止;

  • 如果扫描到操作数,则直接进栈;
  • 如果扫描到运算符,则弹出两个栈顶元素(先弹出的是左操作数,后弹出的右操作数),执行相应运算并压回栈中;

2、当表达式扫描结束,栈顶元素便是计算结果。大功告成!😁😁😁

代码
//两数的四则运算
double value(double op1,double op2,char ch){
    switch (ch) {
        case '+': return op1+op2;break;
        case '-': return op1-op2;break;
        case '*': return op1*op2;break;
        case '/': return (op1*1.0)/op2;break;
    }
}

//前缀表达式求值
double calculate(char* str){
    stack<char> s;
    //将表达式倒序
    int i=0;
    while(str[i]!='\0'){
        s.push(str[i]);
        ++i;
    }
    stack<double> result;
    //倒序遍历后缀表达式
    while(!s.empty()){
        char temp=s.top();
        s.pop();
        if(result.empty()||temp>='0'&&temp<='9')
            result.push(temp-'0');
        else{
            double op1=result.top();
            result.pop();
            double op2=result.top();
            result.pop();
            result.push(value(op1,op2,temp));
        }
    }
    return result.top();
}
结果

在这里插入图片描述

4、后缀表达式求值

思路

1、从左往右扫描表达式中的每个元素,直到最后一个元素为止;

  • 如果扫描到操作数,则直接进栈;
  • 如果扫描到运算符,则弹出两个栈顶元素(先弹出的是右操作数,后弹出的左操作数),执行相应运算并压回栈中;

2、当表达式扫描结束,栈顶元素便是计算结果。大功告成!😁😁😁

代码
//两数的四则运算
double value(double op1,double op2,char ch){
    switch (ch) {
        case '+': return op1+op2;break;
        case '-': return op1-op2;break;
        case '*': return op1*op2;break;
        case '/': return (op1*1.0)/op2;break;
    }
}

//后缀表达式计算
double calculate(char*str){
    stack<double> stack;
    double res=0;
    //遍历后缀表达式
    for(int i=0;str[i]!='\0';++i){
        if (str[i]>='0'&&str[i]<='9'){
            stack.push(str[i]-'0');
        }
        else{
            double op2=stack.top();
            stack.pop();
            double op1=stack.top();
            stack.pop();
            double temp=value(op1,op2,str[i]);
            stack.push(temp);
            res+=temp;
        }
    }
    return stack.top();
}
int main(){
	//infix_to_postfix函数为上面中缀转后缀的函数
    cout<<calculate(infix_to_postfix("5/1+(9-2)*4/2"));
    return 0;
}
结果

在这里插入图片描述

5、中缀表达式求值

思路

中缀表达式求值,其实就是先将中缀表达式转换成后缀表达式(前缀表达式),再通过后缀表达式(前缀表达式)的求值方法来计算。
当然你也可以把这两个步骤合二为一,便是以下代码所给出的内容。如果你已经掌握了中缀表达式转后缀表达式并计算的思路的话,下面的代码你应该看得懂,这里就不再赘述思路了。(懒得写了😂😂😂)

代码
//规定优先级
int level(char s){
    if(s=='+' || s=='-')
        return 1;
    else if (s=='*'||s=='/')
        return 2;
        //设括号优先级为0
    else return 0;
}
//四则运算
double value(double op1,double op2,char ch){
    switch (ch) {
        case '+': return op1+op2;break;
        case '-': return op1-op2;break;
        case '*': return op1*op2;break;
        case '/': return (op1*1.0)/op2;break;
    }
}
//中缀表达式求值
double calculate_infix(char* str){
    //数字栈
    stack<double> number_stack;
    //符号栈
    stack<char> symbol_stack;
    for(int i=0;str[i]!='\0';++i){
        //------------------------如果扫描到数字---------------------
        if(number_stack.empty()||str[i]>='0'&&str[i]<='9'){
            number_stack.push(str[i]-'0');
        }
        //------------------------如果扫描到运算符-------------------
        else if(str[i]=='+'||str[i]=='-'||str[i]=='*'||str[i]=='/'){
            //如果当前运算符的优先级>栈顶符号优先级,则直接进栈
            if(symbol_stack.empty()|| level(str[i])> level(symbol_stack.top()))
                symbol_stack.push(str[i]);
            //如果当前运算符的优先级<=栈顶符号的优先级
            else{
                //依次弹出优先级高于或等于当前符号的所有符号,并同时弹出数字栈中的两个数字作为操作数。注意先后顺序。
                while(!symbol_stack.empty()&&level(symbol_stack.top())>= level(str[i])){
                    double op2=number_stack.top();
                    number_stack.pop();
                    double op1=number_stack.top();
                    number_stack.pop();
                    //将计算结果压入数字栈
                    number_stack.push(value(op1,op2,symbol_stack.top()));
                    //符号出栈
                    symbol_stack.pop();
                }
                symbol_stack.push(str[i]);//最后把当前符号入栈
            }
        }
        //-----------------如果扫描到界限符-------------------
        else{
            if(str[i]=='(')
                symbol_stack.push(str[i]);
            else{
                //遇到右括号')'依次弹出符号栈内运算符,和数字栈内的两个运算符,做计算,直到遇到左括号'('为止
                while(symbol_stack.top()!='('){
                    double op2=number_stack.top();
                    number_stack.pop();
                    double op1=number_stack.top();
                    number_stack.pop();
                    //将计算结果压入数字栈
                    number_stack.push(value(op1,op2,symbol_stack.top()));
                    //符号出栈
                    symbol_stack.pop();
                }
                symbol_stack.pop();
            }
        }
    }
    //将符号栈所有运算符出栈,与数字栈剩余数字做运算
    while(!symbol_stack.empty()){
        double op2=number_stack.top();
        number_stack.pop();
        double op1=number_stack.top();
        number_stack.pop();
        //将计算结果压入数字栈
        number_stack.push(value(op1,op2,symbol_stack.top()));
        //符号出栈
        symbol_stack.pop();
    }
    return number_stack.top();
}
结果

在这里插入图片描述

四、总结

应该没什么人会在意总结吧,随便写写咯,指出一下不足之处吧。😁😁😁
不足之处就是,只能计算一位整数的加减乘除,小数呀、两位数啥的都不行。🙄🙄🙄
欢迎指教😛😛😛
在这里插入图片描述

  • 16
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
下面是C++中求解中缀表达式、后缀表达式和前缀表达式的代码,其中包括了表达式求值算法实现: 1. 求解中缀表达式: ```c++ #include <iostream> #include <stack> #include <string> using namespace std; int priority(char c) { // 定义运算符优先级 if (c == '*' || c == '/') { return 2; } else if (c == '+' || c == '-') { return 1; } else { return 0; } } double calculate(double a, double b, char c) { // 定义运算符操作 switch (c) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: return 0; } } double evaluateInfix(string expression) { // 中缀表达式求值 stack<double> nums; // 存放数字 stack<char> ops; // 存放运算符 int len = expression.length(); for (int i = 0; i < len; i++) { char c = expression[i]; if (isdigit(c)) { // 如果是数字 double num = 0; while (i < len && isdigit(expression[i])) { num = num * 10 + (expression[i] - '0'); i++; } nums.push(num); i--; } else if (c == '(') { // 如果是左括号 ops.push(c); } else if (c == ')') { // 如果是右括号 while (!ops.empty() && ops.top() != '(') { double b = nums.top(); nums.pop(); double a = nums.top(); nums.pop(); char op = ops.top(); ops.pop(); nums.push(calculate(a, b, op)); } ops.pop(); } else { // 如果是运算符 while (!ops.empty() && priority(ops.top()) >= priority(c)) { double b = nums.top(); nums.pop(); double a = nums.top(); nums.pop(); char op = ops.top(); ops.pop(); nums.push(calculate(a, b, op)); } ops.push(c); } } while (!ops.empty()) { // 处理剩余的运算符 double b = nums.top(); nums.pop(); double a = nums.top(); nums.pop(); char op = ops.top(); ops.pop(); nums.push(calculate(a, b, op)); } return nums.top(); } int main() { string expression = "1+2*3-4/2"; double result = evaluateInfix(expression); cout << expression << " = " << result << endl; return 0; } ``` 2. 求解后缀表达式: ```c++ #include <iostream> #include <stack> #include <string> using namespace std; double calculate(double a, double b, char c) { // 定义运算符操作 switch (c) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: return 0; } } double evaluatePostfix(string expression) { // 后缀表达式求值 stack<double> nums; // 存放数字 int len = expression.length(); for (int i = 0; i < len; i++) { char c = expression[i]; if (isdigit(c)) { // 如果是数字 double num = 0; while (i < len && isdigit(expression[i])) { num = num * 10 + (expression[i] - '0'); i++; } nums.push(num); i--; } else { // 如果是运算符 double b = nums.top(); nums.pop(); double a = nums.top(); nums.pop(); nums.push(calculate(a, b, c)); } } return nums.top(); } int main() { string expression = "123*+4-2/"; double result = evaluatePostfix(expression); cout << expression << " = " << result << endl; return 0; } ``` 3. 求解前缀表达式: ```c++ #include <iostream> #include <stack> #include <string> using namespace std; double calculate(double a, double b, char c) { // 定义运算符操作 switch (c) { case '+': return a + b; case '-': return a - b; case '*': return a * b; case '/': return a / b; default: return 0; } } double evaluatePrefix(string expression) { // 前缀表达式求值 stack<double> nums; // 存放数字 int len = expression.length(); for (int i = len - 1; i >= 0; i--) { char c = expression[i]; if (isdigit(c)) { // 如果是数字 double num = 0; int j = i; while (j >= 0 && isdigit(expression[j])) { num = num + (expression[j] - '0') * pow(10, i - j); j--; } nums.push(num); i = j + 1; } else { // 如果是运算符 double a = nums.top(); nums.pop(); double b = nums.top(); nums.pop(); nums.push(calculate(a, b, c)); } } return nums.top(); } int main() { string expression = "-+*123/84"; double result = evaluatePrefix(expression); cout << expression << " = " << result << endl; return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只平平无奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值