一文看懂中缀表达式转化成后缀表达式

中缀表达式转化成后缀表达式代码实现心得

通过堆栈的学习,我们已经知道想要将中缀表达式转化成后缀表达式,有以下几步操作
1.对于运算数:直接输出
2. 对于左括号:直接压入栈中
3. 对于右括号将栈顶的运算符弹出并输出,若栈顶元素不是左括号,继续弹出,直到遇到左括号(出栈,但是不输出)
4. 对于运算符:
• 若优先级大于栈顶运算符时,则把他压栈
• 若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出:再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈
5. 若各对象处理完毕,则把堆栈中残留的运算符一并输出
也就是说,通过这些操作便能顺利的将中缀表达式转化成后缀表达式,那么我们应该思考如何实现呢?
由于这里运算数以及不同的操作符要进行的操作时不同的,所以可以想到整体用一个if-else语句块实现,我们注意到,遇到右括号的时候要一直找,直到找到左括号位置,而且左括号得弹出而不能输出,这里我们考虑用while,对于运算符,有一个关键词叫做优先级,那我们可以考虑编一个函数level,将优先级定义为’)’ > ‘*’ , ’/’ > ‘+’ ,‘-’通过返回值大小的比较来进一步考虑该如何进行下一步的操作,最后一步,当循环中缀表达式入栈完毕后,若栈不为空,说明有东西遗漏了,上代码:

#include <iostream>
#include<stack>
#include<cstdio>
#include<string>
using namespace std;

int level(char c)
{
    int re = 0;
    if(c == '(')//处理当栈顶元素为‘(’时的情况
        re = -1;
    if(c == '+' || c == '-')
        re = 1;
    else if(c == '*' || c == '/')
        re = 2;
    else if(c == ')')
        re = 3;
    return re;
}

int main()
{
    string str;
    stack<char>s;
    cin>>str;
    for(int i = 0; i < str.size(); i++){
        if(isdigit(str[i]) || (str[i] >= 'a' && str[i] <= 'z') ||(str[i] >= 'A' && str[i] <= 'Z'))//运算数直接输出
            printf("%c", str[i]);
        else if(str[i] == '(')
            s.push(str[i]);
        else if(str[i] == ')'){
            while(s.top() != '('){
                printf("%c", s.top());
                s.pop();
            }//执行完while之后,s.top = '(',此时需要将栈顶元素弹出,但是不打印
            s.pop();
        }
        else if(!s.empty() &&level(str[i]) <= level(s.top())){//首先保证栈非空,否则调用s.top时会出错;若优先级小于等于栈顶运算符优先级
            printf("%c", s.top());//打印栈顶元素并弹出
            s.pop();
            while(!s.empty() && level(str[i]) <= level(s.top())){
                printf("%c",s.top());
                s.pop();
            }
            s.push(str[i]);
        }
        else if(level(str[i]) != 0)
            s.push(str[i]);
    }
    while(!s.empty()){//如果还有操作符
        printf("%c",s.top());
        s.pop();
    }
    return 0;
}

写出了第一代代码之后发现一个问题,就是如果数字是多位数,连续输出多个数字时会连在一起,有没有办法让两个数字之间有间隔,数字和运算符,运算符与运算符连续呢,那我就想到了增加一个判断,最近一次输出的类型是啥,若为数字,当后一次输出也为数字时,加个空格,其他情况都不加,于是就有了第二版的代码

#include <iostream>
#include<stack>
#include<cstdio>
#include<string>
using namespace std;

int level(char c)
{
    int re = 0;
    if(c == '(')
        re = -1;
    if(c == '+' || c == '-')
        re = 1;
    else if(c == '*' || c == '/')
        re = 2;
    else if(c == ')')
        re = 3;
    return re;
}

int main()
{
    string str;
    int num = 0;
    int type;//记录前面输出的类型,1表示前面输出了运算数,2表示前面输出了运算符
    stack<char>s;
    cin>>str;
    for(int i = 0; i < str.size(); i++){
        if(isdigit(str[i]))//如果输入为数字
        {
            num = num * 10 + (str[i] - '0');
        }
        else if(num != 0){//输入不是数字,且运算数不为0
            if(type == 1)
                printf(" %d", num);
            else
                printf("%d", num);
            type = 1;
            num = 0;
        }
        if(str[i] >= '0' && str[i] <='9'){

        }
        else if((str[i] >= 'a' && str[i] <= 'z') ||(str[i] >= 'A' && str[i] <= 'Z'))//运算数直接输出
            printf("%c", str[i]);
        else if(str[i] == '(')
            s.push(str[i]);
        else if(str[i] == ')'){
            while(s.top() != '('){
                printf("%c", s.top());
                s.pop();
            }//执行完while之后,s.top = '(',此时需要将栈顶元素弹出,但是不打印
            s.pop();
            type = 2;//最后一个是运算符,type变成2
        }
        else if(!s.empty() &&level(str[i]) <= level(s.top())){//首先保证栈非空,否则调用s.top时会出错;若优先级小于等于栈顶运算符优先级
            printf("%c", s.top());//打印栈顶元素并弹出
            s.pop();
            while(!s.empty() && level(str[i]) <= level(s.top())){
                printf("%c",s.top());
                s.pop();
            }
            s.push(str[i]);
            type = 2;
        }
        else if(level(str[i]) != 0)
            s.push(str[i]);
    }
    if(num != 0){
        if(type == 1)
            printf(" %d", num);
        else
            printf("%d", num);
    }
    while(!s.empty()){//如果还有操作符
        printf("%c",s.top());
        s.pop();
    }
    return 0;
}

经过第二版之后,可以说程序已经不错了,可以实现字母,多位整数的中缀表达式转化成后缀表达式,那么如何实现小数成了我下一个为之努力的目标,我的思路时是找到小数点,小数点前后整合成一个浮点数,再输出一个浮点数,这是我一个好盆友提醒我,你思维定势了,你完全可以将‘.’当成一个操作符进行输出,转念一想,好有道理,而且实现起来简单好多,于是就有了第三版

#include <iostream>
#include<stack>
#include<cstdio>
#include<string>
using namespace std;

int level(char c)
{
    int re = 0;
    if(c == '(')
        re = -1;
    if(c == '+' || c == '-')
        re = 1;
    else if(c == '*' || c == '/')
        re = 2;
    else if(c == ')')
        re = 3;
    return re;
}

int main()
{
    string str;
    int num = 0;
    int type;//记录前面输出的类型,1表示前面输出了运算数,2表示前面输出了运算符
    stack<char>s;
    cin>>str;
    for(int i = 0; i < str.size(); i++){
        if(str[i] >= '0' && str[i] <= '9')//如果输入为数字
        {
            num = num * 10 + (str[i] - '0');
        }
        else if(num != 0){//输入不是数字,且运算数不为0
            if(type == 1)
                printf(" %d", num);
            else
                printf("%d", num);
            type = 1;
            num = 0;
        }
        if(str[i] >= '0' && str[i] <='9'){

        }
        else if(str[i] == '.'){
            type = 2;
            printf(".");
        }
        else if((str[i] >= 'a' && str[i] <= 'z') ||(str[i] >= 'A' && str[i] <= 'Z'))//运算数直接输出
            printf("%c", str[i]);
        else if(str[i] == '(')
            s.push(str[i]);
        else if(str[i] == ')'){
            while(s.top() != '('){
                printf("%c", s.top());
                s.pop();
            }//执行完while之后,s.top = '(',此时需要将栈顶元素弹出,但是不打印
            s.pop();
            type = 2;//最后一个是运算符,type变成2
        }
        else if(!s.empty() &&level(str[i]) <= level(s.top())){//首先保证栈非空,否则调用s.top时会出错;若优先级小于等于栈顶运算符优先级
            printf("%c", s.top());//打印栈顶元素并弹出
            s.pop();
            while(!s.empty() && level(str[i]) <= level(s.top())){
                printf("%c",s.top());
                s.pop();
            }
            s.push(str[i]);
            type = 2;
        }
        else if(level(str[i]) != 0)
            s.push(str[i]);
    }
    if(num != 0){
        if(type == 1)
            printf(" %d", num);
        else
            printf("%d", num);
    }
    while(!s.empty()){//如果还有操作符
        printf("%c",s.top());
        s.pop();
    }
    return 0;
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值