You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
6.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <bits/stdc++.h>
using namespace std;
//后缀表达式,又称为逆波兰表达式
#pragma region C++实现的中缀表达式转后缀表达式
const int MAXSIZE = 256;
/*
将中缀表达式转换为后缀表达式
参数:infix 指向中缀表达式,以回车键即\n结尾。
postfix 指向后缀表达式临时缓冲区,用来存放转换后的结果。
附转换规则从左到右遍历中缀表达式的每个数字和符号若是数字则直接保存在postfix数组中若是符号则判断其与栈顶符号的优先级是右括号或者优先级不大于栈顶符号则栈顶元素依次出栈并输出直到遇到左括号或者栈空时才将刚才的那个符号入栈。
*/
int InfixToPostfix(char *infix, char *postfix) {
stack<char> s;
char c, e;
int j = 0, i = 0;
c = *(infix + i); //取出中缀表达式中的第一个字符
i++;
while ('\n' != c) //遇到换行符,表示转换结束
{
while (c >= '0' && c <= '9') //先判断一下取出的字符是否是数字如果是数字的话则直接存入postfix数组
{
postfix[j++] = c;
c = *(infix + i);
i++;
if (c < '0' || c > '9') //如果不是数字,则在后面添加空格,以便区分各个符号
{
postfix[j++] = ' ';
}
}
if (')' == c) //不是数字,则判断是否为右括号。[括号的优先级最高,所以,如果是右括号的话,就得先进行括号里的各种运算]
{
e = s.top();
s.pop();
while ('(' != e) //直到遇到左括号为止
{
postfix[j++] = e;
postfix[j++] = ' ';
e = s.top();
s.pop();
}
} else if ('+' == c || '-' == c) //如果是加减号,因为他俩的优先级最低了,所以此时先将栈里的所有符号出栈后(除非遇到左括号),再把此符号入栈
{
if (!(s.size())) //如果是空栈,则直接将加减号入栈
{
s.push(c);
} else//如果不是空栈,首先将所有优先级大于加减的出栈,然后再把加减号入栈
{
do {
e = s.top();
s.pop();
if ('(' == e) {
s.push(e);
} else {
postfix[j++] = e;
postfix[j++] = ' ';
}
} while (s.size() && '(' != e); //将栈里的所有符号出栈(除非遇到左括号)
s.push(c); //最后将新来的加减号再入栈
}
} else if ('*' == c || '/' == c || '(' == c) //如果是乘除号或左括号,因为他们的优先级高,所以直接入栈。
{
s.push(c);
} else if ('\n' == c) //判断一下,所有符号是否都已转换完成
{
break;
} else //能走到这个else的都是我不认识的符号了
{
// printf("\nError:input error,the character %d cann't recognize!\n",c);
return -1;
}
c = *(infix + i); //取出下一个字符进行转换
i++;
}
while (s.size()) //转换完成后,栈里可能还有没出栈的运算符号
{
e = s.top();
s.pop();
postfix[j++] = e;
postfix[j++] = ' ';
}
return true;
}
/*
计算后缀表达式的结果
参数arr使用空格分隔的后缀表达式字符串。例arr="31 5 + "
result 保存计算完毕后的结果
注:如何利用栈来计算后缀表达式的结果:依次取出后缀表达式中的符号进行比较,如果是数字,则直接入栈;如果是符号,则出栈两次,弹出两个要计算的因数,进行计算,之后再将计算结果入栈。知道后缀表达式中所有符号都已比较完毕。
*/
double Calculate(char *arr) {
double d, e, f; //d,e 存放两个因数。f存放d,e计算后的结果.
stack<double> s;
char *op; //存放后缀表达式中的每个因数或运算符
char *buf = arr; //声明bufhe saveptr两个变量是strtok_r函数的需要。
while ((op = strtok(buf, " ")) != NULL) //利用strtok_r函数分隔字符串
{
buf = NULL;
switch (op[0]) {
case '+':
d = s.top();
s.pop();
e = s.top();
s.pop();
f = d + e;
s.push(f);
break;
case '-':
d = s.top();
s.pop();
e = s.top();
s.pop();
f = e - d;
s.push(f);
break;
case '*':
d = s.top();
s.pop();
e = s.top();
s.pop();
f = d * e;
s.push(f);
break;
case '/':
d = s.top();
s.pop();
e = s.top();
s.pop();
f = e / d;
s.push(f);
break;
default:
d = atof(op); //不是运算符就肯定是因数了。所以用atof函数将字符串转换为double类型
s.push(d);
break;
}
}
double result = s.top();
s.pop();
return result;
}
#pragma endregion C++实现的中缀表达式转后缀表达式
// 示意图:
// https://www.cnblogs.com/lulipro/p/7450886.html
char in[MAXSIZE] = {0};
char postfix[MAXSIZE] = {'\0'};
int main() {
//给的测试用例,后缀表达式的运算符号居然是贴在一起的,还需要手动将其分离开就行了。
string s = "";
int pos = 0;
getline(cin, s);
for (int i = 0; i < s.size(); ++i) {
if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/') {
postfix[pos] = s[i];
postfix[pos + 1] = ' ';
pos += 2;
} else {
postfix[pos] = s[i];
pos++;
}
}
//输出后缀表达式
puts(postfix);
//计算后缀表达式
cout << Calculate(postfix);
return 0;
}