前缀、中缀、后缀表达式之间的相互转换及部分实现

背景介绍

前缀表达式(又称为波兰表达式)
中缀表达式
后缀表达式(又称为逆波兰表达式)

平时我们见到的都是:2+3*5,这样的算数表达式(中缀),我们数学中也就是用这种
这种表达式(中缀)只适合人来读写,不适合计算机,所以为了方便计算机读取正确的表达式就有了前缀后缀表达式

本文将会介绍 :

前缀转中缀,中缀转前缀
中缀转后缀,后缀转中缀
前后缀之间的相互转换可以用中缀作为中间商来解决,或者也可以构造语法树遍历来解决

前缀转后缀的具体实现代码(构造树实现)
https://www.cnblogs.com/breakthings/p/4053444.html


例子:2+(3-1)*4(中缀,语法树中序遍历可以得到)
231-4 * + (后缀,语法树后序遍历可以得到,其他方法得到也行,表达式不唯一)
+2*-314 (前缀,语法树先序遍历可以得到)

为了方便理解,我画了表达式的 语法树
叶子节点都是,非叶子节点都是运算符。画图很简单就不赘述了

在这里插入图片描述

1. 中缀转前缀

如果仅仅是写题目,仅需把语法树用前序遍历(又称为先序遍历)一遍即可得到答案 +2*-314(前缀表达式)

但一般实现是使用

思路:
  1. 首先要处理字符串,运算符的优先级,多位数字看成整体(比如23看成一个整体而不是2和3),我的例子中没那么复杂
  2. 创建两个栈,一个是数字栈(里面存的是最终结果),一个是运算符栈
  3. 从右往左 扫描中缀表达式
  4. 若是运算符,则与运算符栈顶元素比较优先级:
    若该运算符优先级大于等于栈顶元素,则将该运算符入栈;
    若该运算符优先级小于栈顶元素,则运算符栈内元素出栈并压入数字栈,再与其比较,直到该运算符优先级大于等于栈顶元素的优先级时,将该运算符压入栈中。
  5. 注意:我们先在运算符栈中压入一个‘#’ 规定其优先级为最低 这样解决了开始时候的边界问题)
    注意:遇到右括号直接压入栈中,遇到一个左括号,那么就将运算符栈元素弹出并压入数字栈直到遇到右括号,并且把右括号弹出,停止弹出。这个过程,两个括号都不加入数字栈。
  6. 表达式遍历完后,若运算符栈还有元素,则依次弹出压入数字栈。
  7. 把数字栈元素从栈顶依次弹出,就得到前缀表达式。
代码实现:

例:1-(2+3) 转换前缀是:- 1 + 2 3
例:1+((2+3)*4)-5 转换前缀是:- + 1 * + 2 3 4 5
例:123+((246+39)*48)-55 转换前缀是:- + 123 * + 246 39 48 55

参考博客:https://blog.csdn.net/holly_Z_P_F/article/details/98724274

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=1005;
typedef struct NODE{
    string ch;
    int level;
}NODE;
NODE node[maxn];
string s;
int change(){
    int w1=0;
    for(int i=0;i<s.size();i++){  //划分优先级
        if(s[i]=='*'||s[i]=='/'){
            node[w1].ch=s[i];
            node[w1++].level=2;
        }
        else if(s[i]=='+'||s[i]=='-'){
            node[w1].ch=s[i];
            node[w1++].level=1;
        }
        else if(s[i]=='('||s[i]==')'){
            node[w1].ch=s[i];
            node[w1++].level=0;
        }
        else if(s[i]>='0'&&s[i]<='9'){ //分割字符串
            int j=i;
            while(s[j]>='0'&&s[j]<='9'){ j++;}
            node[w1].ch=s.substr(i,j-i);
            node[w1].level=100;
            w1++;
            i=j-1;
        }
    }
    return w1;
}
void solove(int l){
    NODE ans[maxn]; //结果栈
    NODE q[maxn];  //运算符栈
    int w2=0,w3=0;
    q[w3].ch="#";  q[w3++].level=-1;//先压入 #
    for(int i=l-1;i>=0;i--){
        if(node[i].level==100){
            ans[w2++]=node[i];
        }
        else{
            if(node[i].ch==")") q[w3++]=node[i];
            else if(node[i].ch=="("){
                while(q[w3-1].ch!=")"){
                    w3--; ans[w2++]=q[w3];//压入结果栈
                }
                w3--;
            }
            else{
                while(node[i].level<q[w3-1].level){ //比较优先级
                    w3--; ans[w2++]=q[w3];
                }
                q[w3++]=node[i];
            }
        }
    }
    while(w3!=1){
        w3--;  ans[w2++]=q[w3];
    }
    for(int i=w2-1;i>=0;i--){//倒序输出
        cout<<ans[i].ch<<" ";
    }
    return ;
}
int main(){
    cin>>s;        //输入表达式
    int l=change();//处理表达式
    solove(l);     //转换为前缀表达式
    return 0;
}

2. 前缀转中缀

(这一点网上的资料很少)
例子:+2*-314(前缀)-----> 2+((3-1)*4)(中缀)

思路:

准备一个栈

  1. 从右往左扫描前缀表达式
  2. 遇见数字压入数字栈
  3. 遇见运算符栈,则弹出数字栈的两个元素,并且运算,前后还要添加括号,然后压入栈
    例如:栈中有2和3(2个元素),现在遇见+了,则把 (2+3) 压入栈,栈中现在就有5个元素了,后面的依次类推
    结果中肯定会出现很多多余的括号,也可以解决但是比较复杂就不详细说了
代码实现:

实现起来较为复杂,有机会补上…

3. 中缀转后缀

写答案的话后序遍历的语法树,可以直接得到答案

思路:

和中缀转前缀差不多,只是方向改变了

  1. 从左往右扫描中缀表达式
  2. 其他的与中缀转前缀的操作一样

这里有一篇图解博客,方便大家理解
https://www.cnblogs.com/lanhaicode/p/10776166.html

4. 后缀转中缀

思路:

与前缀转中缀的思路一样

  1. 从右往左扫描后缀表达式
  2. 遇见数字压入数字栈
  3. 遇见运算符栈,则弹出数字栈的两个元素,并且运算,前后还要添加括号,然后压入栈
    例如:栈中有2和3(2个元素),现在遇见+了,则把 (2+3) 压入栈,栈中现在就有5个元素了,后面的依次类推

1 2 3 + 4 *5 - +

例如:
从左往右扫描先碰到+号,取+号前面两个操作数:2,3 得到:(2+3).
继续往下扫碰到*号,取4 和2+3 得到:((2+3)*4)
-号,取(2+3)*4和5得到::(((2+3)*4)-5))
+号:取(2+3)*4-5和1得到::1+(((2+3)*4)-5))
如果把多余的括号省略就是1+(2+3)*4-5


如有错误,不吝赐教

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
为了回答你的问题,我将介绍前缀中缀后缀表达式,并展示如何在它们之间进行转换。 1. 前缀表达式(也称为波兰式): 在前缀表达式中,运算符位于操作数之前。例如,表达式 "2 + 3" 的前缀形式为 "+ 2 3"。 2. 中缀表达式: 中缀表达式是我们通常使用的常规数学表达式形式。它使用括号和运算符的优先级来表示运算顺序。例如,表达式 "2 + 3" 就是一个中缀表达式。 3. 后缀表达式(也称为逆波兰式): 在后缀表达式中,运算符位于相应的操作数之后。例如,表达式 "2 + 3" 的后缀形式为 "2 3 +"。 现在,我将向你展示如何将中缀表达式转换前缀后缀表达式。 从中缀前缀转换: 1. 反转中缀表达式。 2. 将反转的中缀表达式转换为后缀形式。 3. 反转后缀表达式即可得到前缀表达式。 从中缀到后缀转换: 1. 创建一个空和一个空输出列表。 2. 从左到右扫描中缀表达式的每个符号。 - 如果遇到操作数,将其添加到输出列表。 - 如果遇到运算符,将其压入中。 - 如果遇到左括号,将其压入中。 - 如果遇到右括号,则连续弹出顶元素并将其添加到输出列表,直到遇到左括号为止。注意:左括号不会被添加到输出列表中。 如果顶元素是左括号,则将其弹出。 - 如果遇到的运算符具有比顶运算符更高的优先级,将其压入中。 如果遇到的运算符具有与顶运算符相同的优先级,并且是左结合的运算符,则将顶运算符弹出并添加到输出列表中,然后将当前运算符压入中。 如果遇到的运算符具有与顶运算符相同的优先级,并且是右结合的运算符,则将当前运算符压入中。 - 重复步骤2直到扫描完整个中缀表达式。 3. 将中剩余的所有运算符弹出并添加到输出列表中。 4. 输出列表即为转换后的后缀表达式。 希望这个解释对你有帮助!如果你有其他问题,可以继续问我。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值