中缀表达式转后缀表达式代码实现以及快速求法

97 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

中缀表达式转后缀表达式

首先,说明为什么会有中缀转后缀的需求,一般是为了计算机更好的求值运算,我们习惯的常规的中缀表达式需要考虑到括号的优先级,所以计算机很难理解,而后缀表达式只需要从前往后扫描运算即可,这无疑方便与计算机的运算。

规则:

  1. 遇到数值直接输出
  2. 遇到其他的比较优先级,这里可以简单的把+、-、*、/这些符号当成一种比较矫情的符号,他们忍受不了比他们大(优先级高于或等于)的符号在家中带着享福,认为大的符号就应该外出挣钱,而自己和那些比较小的弟弟妹妹则应该待在家里。括号另说。
  3. 括号代表则打包带走的含义。需结合例子自行体会。

实例:

把中缀表达式:a+b-a*((c+d)/e-f)+g 转化为后缀表达式:ab+acd+e/f- { ** }-g+#。如果有大括号等自行调整程序。 Tips:请自己跟着步骤来一遍,只看是看不懂的。 步骤:/ 为转义,避免md语法 a 直接输出 /+ Home中没有比+更大的了,+进入home b 直接输出 /- Home中竟然有比自己大的人(指+),受不了,把+打一顿然后轰出去。/-进入home a 输出 /* home中只有自己的妹妹/-。所以 / * 进入home /( 遇见左括号直接进入 /( 遇见左括号直接进入 c 输出 /+ home中没人(Tips:(左括号起到了隔断家的作用) d 输出 /)home中形成了一对括号,所以资本家把括号内的人都移出了家干活 / / home中无人,/进入 e输出 /- 把/赶出去,/-进入 f输出 /)资本家打包带走 /+ 把家中的* - 赶出去 g输出 最后的最后,家没了,所以家里面的+只能出来干活了 结果: 在这里插入图片描述

#include<iostream>
#include<bits/stdc++.h>
#include<algorithm>
using namespace std;

/*
    系统的说明一下:
    isp表示in stack priority,即栈内优先级
    icp表示in coming priority,即栈外优先级
    优先级表格如下:

    +------+---------+----------+----------+--------+--------+
    操作符 |   #     |   (     |   *,/   | +,-   |     ) |
    isp    |   0     |     1    |   5      |    3   |   6    |
    icp    |   0     |     6    |   4      |    2   |   1    |


    数组中的‘0’用于填充

*/


char isp[7]= {'#','(','0','+','0','*',')'};
char icp[7]= {'#',')','+','0','*','0','('};
stack<char> home;

//得到某元素的isp
int getisp(char a)
{
    if(a=='-')
        a='+';
    if(a=='/')
        a='*';
    for(int i=0; i<7; i++)
        if(a==isp[i])
        {
            return i;
        }
    return -1;
}

//得到某元素的icp
int geticp(char a)
{
    if(a=='-')
        a='+';
    if(a=='/')
        a='*';
    for(int i=0; i<7; i++)
        if(a==icp[i])
        {
            return i;
        }
    return -1;
}

string GetHomeitem(stack<char> h)
{
    string tmp="";
    while(!h.empty())
    {
        tmp+=h.top();
        h.pop();
    }
    reverse(tmp.begin(),tmp.end());
    return tmp;
}

int main()
{
    //s就是中缀表达式
    string s;
    cin>>s;
    //res则是后缀表达式
    string  res="";


    int cnt=1;
    home.push('#');

    for(int i=0; i<s.size(); i++)
    {
        char item = s[i];

        //如果是数,直接输出
        if(geticp(item)==-1)
        {
            res+=item;
            cout<<"NO."<<cnt++<<".  | Scan item :"<< item<<" |  Home(Stack):"<<GetHomeitem(home)<<"  | ";
                cout<<" Res :"<<res<<endl;
        }
        //否则比较优先级
        else{
            char r = home.top();
            while(geticp(item)<getisp(r)&&!home.empty())//只要你比我大,你就要出来
            {

                res+=r;
                home.pop();
                r=home.top();

                cout<<"NO."<<cnt++<<".  | Scan item :"<< item<<" |  Home(Stack):"<<GetHomeitem(home)<<"  | ";
                cout<<" Res :"<<res<<endl;

            }
            if(r=='('&&item==')')
                home.pop();

            if(item!=')')
            {
                home.push(item);
                cout<<"NO."<<cnt++<<".  | Scan item :"<< item<<" |  Home(Stack):"<<GetHomeitem(home)<<"  | ";
                cout<<" Res :"<<res<<endl;
            }

        }
    }
    while(!home.empty())
    {
        res+=home.top();
        home.pop();
        cout<<"NO."<<cnt++<<".  | Scan item : " <<" |  Home(Stack):"<<GetHomeitem(home)<<"  | ";
                cout<<" Res :"<<res<<endl;

    }
    cout<<res<<endl;
    return 0;
}

快速方法

11/12/2021 Update

  1. 首先按照运算符优先级对所有运算单位加括号
  2. 把运算符移动到对应的括号后面
  3. 去括号

举例

a/b+(cd-(ef)/g) 有:

  1. 加括号 ((a/b)+(((c *d)-(e *f))/g))
  2. 运算符后移 ((ab)/(((cd)**(ef)*)-g)/)+
  3. 去括号 ab/cd{ ** } e f { /*}-g/+