目录
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 ^ 3
为 2 ^ (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型互相转化的几种方式