示例:
正常表达式:
3*2+15*2-9
后缀表达式:
3 2 * 15 2 * + 9 -
前缀表达式:
- + * 3 2 * 15 2 9
中缀表达式1:
3 * 2 + 15 * 2 - 9
中缀表达式2:
( 3 * 2 ) + ( 15 * 2 ) - 9
思想:
在掌握后缀表达式求值的基础上,将中缀表达式转换为后缀表达式,调用后缀表达式求值函数,完成计算
后缀表达式求值:[C++]数据结构--栈--后缀表达式求值-优快云博客
前缀表达式求值:[C++]数据结构--栈--前缀表达式求值-优快云博客
Tips:前缀表达式和后缀表达式中是将操作数入栈,故栈的数据类型设置为double,而中缀表达式是将计算符号入栈,故栈的数据类型变为char
中缀→后缀转换过程:
表达式不带有()时:
使用一个字符串接收后缀表达式,对于原本的中缀表达式来说,遇到数字部分正常依次写入字符串,遇到计算符号,若栈为空,入栈。
若栈内有计算符号,则将栈外即将入栈的计算符号B与栈内处于栈顶的计算符号A相比较,如果A的优先级大于B,即A出栈,否则B进栈。
若A出栈后在栈内有新的处于栈顶的计算符号C,则B继续与C比较,直至B入栈。若原本的中缀表达式已经全部扫描完毕,栈中还有未出栈的计算符号时,则计算符号依次出栈
带有()时:
在以上基础规则上,加入()两个符号,对于原本的中缀表达式,遇到(直接入栈。遇到计算符号时,若栈顶为(,正常入栈,其余规则同上。遇到)时,将栈中符号依次弹栈,直到遇见(,这个(也弹栈
说明:
1. 支持输入正整数,可输入多数位数字,如15,200等
2.表达式间隔使用空格或,
3.支持加减乘除四种运算
// 中缀表达式求值
/*示例:
正常表达式:
3*2+15*2-9
后缀表达式:
3 2 * 15 2 * + 9 -
前缀表达式:
- + * 3 2 * 15 2 9
中缀表达式1:
3 * 2 + 15 * 2 - 9
中缀表达式2:
( 3 * 2 ) + ( 15 * 2 ) - 9
*/
#include <iostream>
#include <string>
#include <stack>
using namespace std;
// 判断当前字符是否为运算符
bool isoperator(char c)
{
if (c == '+' || c == '-' || c == '*' || c == '/')
{
return true;
}
else
{
return false;
}
}
// 判断当前字符是否为数字
bool isnum(char c)
{
if (c >= '0' && c <= '9')
{
return true;
}
else
{
return false;
}
}
// 获取运算符运算结果
double performoperator(char op, double num1, double num2)
{
if (op == '+')
{
return num1 + num2;
}
else if (op == '-')
{
return num1 - num2;
}
else if (op == '*')
{
return num1 * num2;
}
else if (op == '/')
{
if (num2 != 0)
{
return num1 / num2;
}
else
{
cout << "除数不能为0" << endl;
return -1;
}
}
else
{
cout << "运算符错误" << endl;
return -1;
}
}
// 后缀表达式计算
double postfix(string exp)
{
int n = exp.length();
stack<double> S;
for (int i = 0; i < n; i++)
{
if (exp[i] == ' ' || exp[i] == ',')
{
continue;
}
else if (isnum(exp[i]))
{
double operand = 0;
while (i < exp.length() && isnum(exp[i]))
{
operand = (operand * 10) + (exp[i] - '0');
i++;
}
i--;
S.push(operand);
}
else if (isoperator(exp[i]))
{
double num2 = S.top();
S.pop();
double num1 = S.top();
S.pop();
double res = performoperator(exp[i], num1, num2);
S.push(res);
}
}
return S.top();
}
// 给每个计算符号赋予权重
int weight(char op)
{
int w = -1;
switch (op)
{
case '+':
w = 1;
case '_':
w = 1;
case '*':
w = 2;
case '/':
w = 2;
}
return w;
}
// 比较两个计算符号的权重等级
bool higher(char c1, char c2)
{
int w1 = weight(c1);
int w2 = weight(c2);
return w1 >= w2;
}
// 将中缀表达式转化为后缀表达式,之后调用后缀表达式求值函数,最终返回表达式结果
// 该函数的返回值是字符串,即后缀表达式格式的字符串
string infix(string exp)
{
stack<char> C;
int n = exp.length();
string postfix_s = ""; // 后缀字符串,初始化为空
for (int i = 0; i < n; i++)
{
if (exp[i] == ' ' || exp[i] == ',') // 遇到空格或,正常输入进后缀字符串,如果这里if条件下的语句中加入continue,则不支持多数位数字输入
{
postfix_s = postfix_s + exp[i];
}
else if (isoperator(exp[i])) // 遇到计算符号时
{
while (!C.empty() && C.top() != '(' && higher(C.top(), exp[i])) // 栈非空且栈顶不为(且栈顶符号优先级高于遇到的中缀字符串中符号优先级
{
postfix_s = postfix_s + C.top(); // 弹栈
C.pop();
}
C.push(exp[i]);
}
else if (isnum(exp[i])) // 遇到数字,直接输入后缀字符串
{
postfix_s = postfix_s + exp[i];
}
else if (exp[i] == '(') // 遇到(,直接将(入栈
{
C.push(exp[i]);
}
else if (exp[i] == ')') // 遇到),将栈中符号依次弹栈,直到遇见(
{
while (!C.empty() && C.top() != '(')
{
postfix_s = postfix_s + C.top();
C.pop();
}
C.pop();
}
}
// 如果栈中在(之前还有operator,将它们依次弹栈
while (!C.empty())
{
postfix_s = postfix_s + C.top();
C.pop();
}
return postfix_s;
}
int main()
{
string exp;
cout << "请输入:";//参考用例3 * 2 + 15 * 2 - 9
//正确结果:27
getline(cin, exp);
string res = "";
res = infix(exp);
cout << "= " << res << endl;
double rrr = 0;
rrr = postfix(res);
cout << "=" << rrr << endl;
cin.get();
return 0;
}
参考:
B站搬运的一位印度程序员讲解的视频:栈:中缀到后缀表达式的转换 ( 使用栈来实现 )_哔哩哔哩_bilibili