P1175 表达式的转换

P1175 表达式的转换

题目描述

平常我们书写的表达式称为中缀表达式,因为它将运算符放在两个操作数中间,许多情况下为了确定运算顺序,括号是不可少的,而后缀表达式就不必用括号了。

后缀标记法:书写表达式时采用运算紧跟在两个操作数之后,从而实现了无括号处理和优先级处理,使计算机的处理规则简化为:从左到右顺序完成计算,并用结果取而代之。

例如:8-(3+2*6)/5+4 可以写为:8 3 2 6 * + 5 / - 4 +

其计算步骤为:

8 3 2 6 * + 5 / - 4 +
8 3 12 + 5 / - 4 +
8 15 5 / - 4 +
8 3 - 4 +
5 4 +
9

编写一个程序,完成这个转换,要求输出的每一个数据间都留一个空格。

输入格式

就一行,是一个中缀表达式。输入的符号中只有这些基本符号 0123456789+-*/^(),并且不会出现形如 2*-3 的格式。

表达式中的基本数字也都是一位的,不会出现形如 12 形式的数字。

所输入的字符串不要判错。

输出格式

若干个后缀表达式,第 i + 1 i + 1 i+1 行比第 i i i 行少一个运算符和一个操作数,最后一行只有一个数字,表示运算结果。

样例 #1

样例输入 #1

8-(3+2*6)/5+4

样例输出 #1

8 3 2 6 * + 5 / - 4 + 
8 3 12 + 5 / - 4 + 
8 15 5 / - 4 + 
8 3 - 4 + 
5 4 + 
9

样例 #2

样例输入 #2

2^2^3

样例输出 #2

2 2 3 ^ ^
2 8 ^
256

提示

运算的结果可能为负数,/ 以整除运算。并且中间每一步都不会超过 2 31 2^{31} 231。字符串长度不超过 100 100 100

注意乘方运算 ^ 是从右向左结合的,即 2 ^ 2 ^ 32 ^ (2 ^ 3),后缀表达式为 2 2 3 ^ ^

其他同优先级的运算是从左向右结合的,即 4 / 2 / 2 * 2((4 / 2) / 2) * 2,后缀表达式为 4 2 / 2 / 2 *

保证不会出现计算乘方时幂次为负数的情况,故保证一切中间结果为整数。

解题

思想

解题思路其实没啥难的,照着数据结构敲就是了。
ex的点就是太繁琐了,代码太长(才不是因为懒🥺)

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

在这里插入图片描述

2、后缀表达式的计算

在这里插入图片描述

代码

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


stack<char> st;
deque<char> qu; // 保存后缀表达式
list<int>   ls; // 保存计算结果(int)
string line;    

int getPriority(char op){
    // 获取优先级
    if (op == '+' || op == '-')
    {
        return 0;
    }
    else if (op == '*' || op == '/')
    {
        return 1;
    }
    else
    {
        return 2;
    }
}

int compareOperators(char op1, char op2) {
    // 定义一个函数来比较两个运算符的优先级,new优先级高于栈顶元素停止出栈(return 0)
    // return 1 means op1 is greater then op2
    // op1 is stack's top
    // op2 is new element
    // +-*/^
    if (op1 == '^' && op2 == '^')
    {
        // 注意^是右结合的(两个连续的^优先算右面的),其余运算符号是左结合的
        // 因此认为第二个(new)的^优先级更高,所以不必弹出栈顶元素
        return 0;
    }
    else
    {
        // 栈顶运算符优先级高于等于new就继续弹出,return 1
        return getPriority(op1) >= getPriority(op2);
    }    
}

bool isPriority(char op){
    // 判断是否是运算符
    return op == '+' || op == '-' || op == '*' || op == '/' || op == '^';
}

int computer(int a, int b, char priority){
    // 后缀表达式的计算
    switch (priority)
    {
    case '+':
        return a+b;
        break;
    
    case '-':
        return a-b;
        break;

    case '*':
        return a*b;
        break;

    case '/':
        return a/b;
        break;

    case '^':
        return pow(a,b);
        break;     

    default:
        return -1;
        break;
    }
}

int main( )
{
    // getline(cin,line); // 测试报错,不知道为啥,用cin就过了
    cin >> line;
    // cout << line;

    // 生成后缀表达式
    for (int i = 0; i < line.length(); i++)
    {
        if (line[i] == '(')
        {
            st.push(line[i]);
        }
        else if (line[i] == ')')
        {
            while (st.top()!='(')
            {
                qu.push_back(st.top());
                st.pop();
            }
            st.pop();
        }
        else if (isPriority(line[i]))
        {
            if (st.empty())
            {
                st.push(line[i]);
            }
            else
            {
                while (!st.empty()&& isPriority(st.top()) && compareOperators(st.top(), line[i]))
                {
                    qu.push_back(st.top());
                    st.pop();
                }
                st.push(line[i]);
            }
        }
        else
        {
            // 操作数直接进入后缀表达式
            qu.push_back(line[i]);
        }  
    }
    while (!st.empty())
    {
        // 弹出栈中剩余的运算符
        qu.push_back(st.top());
        st.pop();
    }
    
    // 后缀表达式的计算
    while (!qu.empty())
    {
        if (isPriority(qu.front()))
        {
            // 打印当前阶段的后缀表达式
            deque<char> quBackup = qu; // 保存队列qu的副本
            for(auto it = ls.begin(); it != ls.end(); it++ )
            {
                cout<<*it<<' ';
            }
            while (!quBackup.empty())
            {
                cout << quBackup.front() << ' ';
                quBackup.pop_front();
            }
            cout << endl;

            // 遇到运算符进行计算
            int b=ls.back();
            ls.pop_back();
            int a=ls.back();
            ls.pop_back();
            ls.push_back(computer(a,b,qu.front()));
            qu.pop_front();
        }
        else
        {   
            // 转换为int放入链表
            ls.push_back(qu.front() - '0');
            qu.pop_front();
        }
    }
    // 输出最终结果
    cout << ls.back();

    return 0;
}

踩坑

string、char和int的互相转换

注意转换方法,+-'0'的方法只适用于1位数字的情况
C++中int型与string型互相转化的几种方式

读取字符串的方式

看题解才知道用getline的都不对,用cin就能直接过,不知道为啥

	// getline(cin,line); // 测试报错,不知道为啥,用cin就过了
    cin >> line;
    // cout << line;

参考资料

[1] P1175 表达式的转换
[2] 《数据结构》:中缀表达式转后缀表达式 + 后缀表达式的计算
[3] C++中int型与string型互相转化的几种方式

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值