中缀表达式与后缀表达式

计算中缀表达式”可以称得上是一个特别经典的关于栈的算法题,几乎在所有数据结构教材中都会涉及,而且很多公司面试或者笔试的时候都会把这道题作为一个考察点。可以说,这是一道必须要掌握的算法题。中缀表达式、后缀表达式等概念在这里就不赘述了,让我们直奔主题。
题目:输入一个中缀表达式,计算其结果。
输入的前提假设:
(1)只考虑+、-、*、/这四种运算符,中缀表达式中只有一种括号:();
(2)输入的中缀表达式中只有整数,没有小数;
(3)假定输入是合法的。
很多文章或课本喜欢一步到位,直接讨论如何从中缀表达式计算结果。但对于初学者来说,跨度未免大了点。这里循序渐进,从易到难,先讨论如何将中缀表达式转化为后缀表达式,再讨论如何计算后缀表达式。最后在前面两步的基础上,讨论如何一步到位,直接计算中缀表达式的结果:
一、如何将中缀表达式转化为后缀表达式
        在日常应用中,算术表达式中运算符总是出现在两个操作数之间,例如5*(7-2*3)+8/2,这种形式称为中缀表达式。计算一个中缀表达式需要知道运算符的优先级和结合性。乘除是高优先级,加减是低优先级,优先级相同时他们都是左结合的,也就是从左计算到右。有括号就要计算括号内的表达式。
中缀表达式利于人的理解,但不便于计算机的处理。因此需要将中缀表达式转换成后缀表达式,以方便计算机处理。所谓后缀表达式就是将运算符放在运算数之后。后缀表达式也称为逆波兰表达式。
比如:
中缀表达式为:1+(2-3)*4+4/2
对应后缀表达式为:1 2 3 - 4* + 4 2 / +
如何将一个中缀表达式转化为后缀表达式?我们需要借助栈的力量,用它来存放运算符。算法流程如下:
首先将各种运算符(包括括号)的优先级排列如下(数字越大,优先级越高):
1:(
2:+ -
3:* /
4:)
对输入的中缀表达式从左到右遍历:
1)如果遇到数字,直接添加到后缀表达式末尾;
2)如果遇到运算符+、-、*、/:
先判断栈是否为空。若是,则直接将此运算符压入栈。若不是,则查看当前栈顶元素。若栈顶元素优先级大于或等于此操作符级别,则弹出栈顶元素,将栈顶元素添加到后缀表达式中,并继续进行上述判断。如果不满足上述判断或者栈为空,将这个运算符入栈。要注意的是,经过上述步骤,这个运算符最终一定会入栈。
3)如果遇到括号:
如果是左括号,直接入栈。如果是右括号,弹出栈中第一个左括号前所有的操作符,并将左括号弹出。(右括号别入栈)。
4)字符串遍历结束后,如果栈不为空,则弹出栈中所有元素,将它们添加到后缀表达式的末尾,直到栈为空。
二、计算后缀表达式
后缀表达式的计算就相当简单了。准备一个数字栈。从左到右扫描后缀表达式,如果是数字,放入数字栈。如果是符号,从数字栈中弹出两个数字,第一个取出的数字为右运算数,第二个为左运算数,进行运算。然后将结果放进数字栈中。如此反复,直到读完整个表达式后,留在数字栈中的那个数字就是最终结果。
C++代码如下,要注意,下面的代码默认中缀表达式中所有数字都是整数,并且都在0到9之间。而且计算结果都是整数(比如5/2=2)。

#include<iostream>
#include<string>
#include<stack>  

using namespace std;  

int getPriority(char ch)
{
    //获取优先级
    if (ch == ‘(‘) return 1;
    else if (ch == ‘+‘ || ch == ‘-‘) return 2;
    else if (ch == ‘*‘ || ch == ‘/‘) return 3;
    else return 4;
}  

string getPostfixExpression(string str)
{
    //将中缀表达式转化为后缀表达式
    //默认输入是合法的
    stack<char> mystack;
    int size = str.size();
    int i = 0;
    char tmp;
    string res = "";
    while (i < size) {
        if (str[i] >= ‘0‘ && str[i] <= ‘9‘){
            res.push_back(str[i]);
        }
        elseif (str[i] == ‘+‘ || str[i] == ‘-‘ || str[i] == ‘*‘ || str[i] == ‘/‘) {
            if (mystack.empty()) {
                mystack.push(str[i]);
            }
            else {
                while (!mystack.empty()) {
                    tmp = mystack.top();
                    if (getPriority(tmp) >= getPriority(str[i])) {
                        //弹出栈顶元素
                        res.push_back(tmp);
                        mystack.pop();
                    }
                    else break;
                }
                mystack.push(str[i]);
            }
        }
        else {
            if(str[i]==‘(‘) mystack.push(str[i]);
            else {
                while (mystack.top() != ‘(‘) {
                    tmp = mystack.top();
                    res.push_back(tmp);
                    mystack.pop();
                }
                mystack.pop();
            }
        }
        i++;
    }  

    //遍历完后,若栈非空,弹出所有元素
    while (!mystack.empty()) {
        tmp = mystack.top();
        res.push_back(tmp);
        mystack.pop();
    }
    return res;
}  

int calculator(string str)
{
    //计算后缀表达式的值,默认中缀表达式所有数字都是一位的,在0-9之间
    stack<int> mystack;
    int size = str.size();
    int num1, num2, num3;
    for (int i = 0; i < size; i++) {
        if (str[i] >= ‘0‘ && str[i] <= ‘9‘) {
            mystack.push(str[i] - ‘0‘);
        }
        else {
            num2 = mystack.top();
            mystack.pop();
            num1 = mystack.top();
            mystack.pop();
            if (str[i] == ‘+‘) {
                num3 = num1 + num2;
            }
            else if (str[i] == ‘-‘) {
                num3 = num1 - num2;
            }
            else if (str[i] == ‘*‘) {
                num3 = num1 * num2;
            }
            else if (str[i] == ‘/‘) {
                num3 = num1 / num2;
            }
            mystack.push(num3);
        }
    }
    return mystack.top();
}  

int main()
{
    string str="1+(2-3)*4+4/2";
    cout <<"中缀表达式为:"<< endl << str << endl;
    string res = getPostfixExpression(str);
    cout <<"后缀表达式为:"<< endl << res << endl;
    int num_res = calculator(res);
    cout <<"计算结果:"<< endl << num_res << endl;
    system("pause");
    return 0;
}  

三、直接计算中缀表达式
其实将前面的两步结合起来,就可以得到直接计算的方法。准备一个数字栈和一个符号栈。
从左到右遍历中缀表达式。如果遇到数字,入数字栈。
如果遇到符号(四个运算符以及括号),跟前面的“中缀表达式转后缀表达式”过程一样,对符号栈进行处理。处理过程中,对每一个出栈的运算符:+ - * /,根据“计算后缀表达式”的方法,计算结果(跟数字栈配合)。
如果遍历完中缀表达式后符号栈还非空,就继续出符号栈的运算符,计算,直到符号栈为空。最后数字栈剩下的数字就是结果。
下面给出用C++实现“计算中缀表达式”的代码,里面考虑了“数字不止1位”,并且用浮点型来表示最终运算结果。要求中缀表达式中只能包含整数和运算符(不能包含小数),并且是合法的。

#include<iostream>
#include<string>
#include<stack>  

using namespace std;  

int getPriority(char ch)
{
    //获取优先级
    if (ch == ‘(‘) return 1;
    else if (ch == ‘+‘ || ch == ‘-‘) return 2;
    else if (ch == ‘*‘ || ch == ‘/‘) return 3;
    else return 4;
}  

void calculate(stack<double> &mystack, char operation)
{
    double num1, num2, num3;
    num2 = mystack.top();
    mystack.pop();
    num1 = mystack.top();
    mystack.pop();
    if (operation == ‘+‘) {
        num3 = num1 + num2;
    }
    else if (operation == ‘-‘) {
        num3 = num1 - num2;
    }
    else if (operation == ‘*‘) {
        num3 = num1 * num2;
    }
    else if (operation == ‘/‘) {
        num3 = num1 / num2;
    }  

    mystack.push(num3);
}  

double calculator(string str)
{
    //计算中缀表达式,默认输入是合法的
    stack<double> mystack_number;
    stack<char> mystack_operation;
    int i = 0, j;
    int size = str.size();
    char tmp_operation;
    string tmp_num;
    while (i < size) {
        if (str[i] >= ‘0‘ && str[i] <= ‘9‘) {
            j = i;
            while (j < size && str[j] >= ‘0‘ && str[j] <= ‘9‘) { j++; }
            tmp_num = str.substr(i, j - i);
            mystack_number.push(atoi(tmp_num.c_str()));
            i = j;
        }
        else if (str[i] == ‘+‘ || str[i] == ‘-‘ || str[i] == ‘*‘ || str[i] == ‘/‘) {
            if (mystack_operation.empty()) {
                mystack_operation.push(str[i]);
            }
            else {
                while (!mystack_operation.empty()) {
                    tmp_operation = mystack_operation.top();
                    if (getPriority(tmp_operation) >= getPriority(str[i])) {
                        //计算
                        calculate(mystack_number, tmp_operation);
                        mystack_operation.pop();
                    }
                    else break;
                }
                mystack_operation.push(str[i]);
            }
            i++;
        }
        else {
            if (str[i] == ‘(‘) mystack_operation.push(str[i]);
            else {
                while (mystack_operation.top() != ‘(‘) {
                    tmp_operation = mystack_operation.top();
                    //计算
                    calculate(mystack_number, tmp_operation);
                    mystack_operation.pop();
                }
                mystack_operation.pop();
            }
            i++;
        }  

    }
    //遍历完后,若栈非空,弹出所有元素
    while (!mystack_operation.empty()) {
        tmp_operation = mystack_operation.top();
        //计算
        calculate(mystack_number, tmp_operation);
        mystack_operation.pop();
    }
    return mystack_number.top();
}  

int main()
{
    string str = "1+(2-3)*4+10/2+2*2+2+2/5";
    cout << "中缀表达式为:" << endl << str << endl;
    double num_res = calculator(str);
    cout << "计算结果:" << endl << num_res << endl;
    system("pause");
    return 0;
}  

相信通过这篇文章,大家对这个问题会有所了解。
给出一道思考题:如果加入乘方‘^‘,应该如何处理?要注意,乘方运算是右结合的。
其实很简单。只有两处修改:
1)将乘方添加到优先级中:

1:(
2:+ -
3:* /
4:^
5:)
2)在读中缀表达式的时候,如果读到乘方^,就将它放进符号栈中。因为乘方的优先级是最高的,而且是右结合的,所以无论它前面出现的是什么运算,这些运算都不能执行。而且它本身能否执行也是不知道的,因此只能进栈。

【参考资料】

https://blog.csdn.net/sinat_27908213/article/details/80273557

2019-02-13

23:09:01

原文地址:https://www.cnblogs.com/zhengxunjie/p/10372329.html

时间: 2024-10-13 18:43:02

中缀表达式与后缀表达式的相关文章

中缀表达式转为后缀表达式

** * 中缀表达式转后缀表达式 * * 作用:将一长串计算表达式转换为计算机易于操作的字符序列,用于计算器的设计 *  * 参与转换运算符 * +-/*()^% * * * 使用StringBuilder来保存转换出的后缀表达式 * 使用栈来操作运算符 * * * 转换原则 * 1.上述字符中()没有优先级值,+-优先级值为1,/*%优先级值为2,^优先级值为3 * 2.对于一个待计算的表达式,从左向右逐个检查每个字符 * 3.遇到数字,直接append到StringBuilder * 4.遇

栈的应用之中缀表达式转后缀表达式

1,中缀表达式的定义及为什么要将中缀表达式转换为后缀表达式? 中缀表达式(中缀记法) 中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间.中缀表达式是人们常用的算术表示方法. 虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值.对计算机来说,计算前缀或后缀表达式的值要比中缀表达式简单. 比如,计算机计算后缀表达式的过程如下----后缀表达式的计算机求值: 从左

ZH奶酪:Python 中缀表达式转换后缀表达式

实现一个可以处理加减乘数运算的中缀表达式转换后缀表达式的程序: 一个输入中缀表达式inOrder 一个输出池pool 一个缓存栈stack 从前至后逐字读取inOrder 首先看一下不包含括号的: (1)操作数:直接输出到pool (2)操作符:判断当前操作符与stack[top]操作符的优先级 <1>当前操作符优先级高于stack[top]:将当前操作符添加到stack中: <2>当前操作符优先级低于或等于stack[top]:从stack[top]开始出栈,直到stack[to

经典白话算法之中缀表达式和后缀表达式

一.后缀表达式求值 后缀表达式也叫逆波兰表达式,其求值过程可以用到栈来辅助存储. 假定待求值的后缀表达式为:6  5  2  3  + 8 * + 3  +  *,则其求值过程如下: (1)遍历表达式,遇到的数字首先放入栈中,依次读入6 5 2 3 此时栈如下所示: (2)接着读到"+",则从栈中弹出3和2,执行3+2,计算结果等于5,并将5压入到栈中. (3)然后读到8(数字入栈),将其直接放入栈中. (4)读到"*",弹出8和5,执行8*5,并将结果40压入栈中

[转]中缀表达式、前缀表达式、后缀表达式的相互转换

--------------------------------后缀转中缀---------------------------------------------- 1.建立一个栈,从左向右扫描后缀表达式,遇到运算数则压入栈: 2.遇到运算符就把栈顶两个元素出栈,执行运算,得到的结果作为新的运算符再压入栈: 3.依次走到表达式结尾: 例:把逆波兰式(即后缀表达式)ab+c*转换为中缀表达式: 1)a入栈(0位置) 2)b入栈(1位置) 3)遇到运算符"+",将a和b出栈,执行a+b的

数据结构中缀表达式转后缀表达式以及后缀转中缀表达式

最近一直在看数据结构这本书,我相信,对于每个程序员来说,数据结构都尤为重要.为什么要学,可以看看这位博友的认识http://blog.csdn.NET/sdkfjksf/article/details/54380659 直入主题:将中缀表达式转为后缀表达式 以及将后缀表达式转为前缀表达式的实现. 关于后缀转中缀,中缀转后缀的理论介绍,请先阅读其互转的理论知识,或者我转发的这篇文章,这里不再累赘,最好参考<数据结构与算法描述Java语言版>,接下来将会用java写. 一.首先,怎么实现中缀表达式

数据结构——栈——中缀表达式和后缀表达式

什么是中缀表达式,什么是后缀表达式 我们一般看见的多项式计算都是中缀表达式构成的:1+2*3+4/3 类似这种,为什么说是中缀呢?因为它的计算符号都是在两个数中间的. 那么自然而然的明白了后缀表达式是一种计算符号在两个数后面的. 如123*+43/+ 中缀表达式和后缀表达式有什么关系? 其实仔细你就会发现,上面给出的式子其实都是一样的,只是计算的顺序在后缀表达式中你看不懂而已. 因为我们习惯去看中缀表达式的计算. 其实他们之间是可以互相转换的.他们也可以表达同一个意思,同一个计算式子. 为什么会

表达式的计算(中缀表达式转为后缀表达式或逐步计算)

算数表达式的计算,也是很基础的一个问题.花了点时间写了下. 网上很多正确代码.但没有详细说明.虽然不复杂,但是还是写详细点.只有仔细思考过.问题才会在头脑中,觉得简单. 基本有2种方法. 1)中缀表达式转为后缀表达式,是最简洁有力的方法. 2)符合人的计算思路的逐步方法,不推荐使用,只适合锻炼下逻辑能力. 一.中缀表达式转为后缀表达式,是最简洁有力的方法. //更简洁通用的算法,就是把中缀表达式转换为后缀表达式.后缀表达式:不包含括号,运算符放在两个运算对象的后面. //一,无括号的n级符号算法

将中缀表达式转换为后缀表达式,然后利用栈对表达式求值。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="js.js"></script> </head> <body> 输入中缀表达式空格分隔 例如 2 + 3 <input type=

中缀表达式转换为后缀表达式(1042)

描述 中缀表达式是一个通用的算术或逻辑公式表示方法,操作符是以中缀形式处于操作数的中间(例:3 + 4),中缀表达式是人们常用的算术表示方法.后缀表达式不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:(2 + 1) * 3 , 即2 1 + 3 *.利用栈结构,将中缀表达式转换为后缀表达式.(测试数据元素为单个字符) input 中缀表达式 output 后缀表达式 样例输入 A+(B-C/D)*E 样例输出 ABCD/-E