309 lines
8.6 KiB
C++
309 lines
8.6 KiB
C++
#include <bits/stdc++.h>
|
||
|
||
using namespace std;
|
||
/**
|
||
从后缀表达式建立表达式树
|
||
比如现在有以下一个后缀表达式:
|
||
a b + c d e + * *
|
||
根据这个后缀表达式建立二叉表达式树,算法如下:
|
||
1. 依次读取表达式;
|
||
2. 如果是操作数,则将该操作数压入栈中;
|
||
3. 如果是操作符,则弹出栈中的两个操作数,第一个弹出的操作数作为右孩子,第二个弹出的操作数作为左孩子;然后再将该操作符压入栈中。
|
||
这样下去,就可以建立一颗完整的表达式树。
|
||
*/
|
||
// https://www.cnblogs.com/Running-Time/p/4922670.html
|
||
typedef long long LL;
|
||
const int N = 1e5 + 10;
|
||
const int INF = 0x3f3f3f3f;
|
||
const int MOD = 1e9 + 7;
|
||
|
||
/*
|
||
表达式求值,逆波兰式(后缀表达式)算法
|
||
输入(可以有空格,支持小数,实现'+-/*%'): ((1+2)*5+1)/4=
|
||
注意:取模一定是要整型,实现版本数字全是double,强制类型转换可能倒置错误
|
||
转换为后缀表达式: 得到:1 2 + 5 * 1 + 4 / =
|
||
计算后缀表达式:得到:4.00
|
||
*/
|
||
bool is_digit(char ch) {
|
||
return '0' <= ch && ch <= '9';
|
||
}
|
||
|
||
struct Exp {
|
||
stack<char> op;
|
||
stack<double> num;
|
||
|
||
int prior(char ch) { //运算符的优先级
|
||
switch (ch) {
|
||
case '+':
|
||
case '-':
|
||
return 1;
|
||
case '*':
|
||
case '%':
|
||
case '/':
|
||
return 2;
|
||
default:
|
||
return 0;
|
||
}
|
||
}
|
||
//中缀表达式转变前缀表达式
|
||
string get_prefix(string s) {
|
||
while (!op.empty()) op.pop();
|
||
op.push('#');
|
||
string ret = "";
|
||
int len = s.length(), i = len - 1;
|
||
while (i >= 0) {
|
||
if (s[i] == ' ' || s[i] == '=') {
|
||
i--;
|
||
continue;
|
||
} else if (s[i] == ')') {
|
||
op.push(s[i--]);
|
||
} else if (s[i] == '(') {
|
||
while (op.top() != '#' && op.top() != ')') {
|
||
ret += op.top();
|
||
ret += ' ';
|
||
op.pop();
|
||
}
|
||
op.pop();
|
||
i--;
|
||
} else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '%') {
|
||
while (prior(op.top()) > prior(s[i])) {
|
||
ret += op.top();
|
||
ret += ' ';
|
||
op.pop();
|
||
}
|
||
op.push(s[i--]);
|
||
} else {
|
||
while (is_digit(s[i]) || s[i] == '.') {
|
||
ret += s[i--];
|
||
}
|
||
ret += ' ';
|
||
}
|
||
}
|
||
while (op.top() != '#') {
|
||
ret += op.top();
|
||
ret += ' ';
|
||
op.pop();
|
||
}
|
||
reverse(ret.begin(), ret.end());
|
||
return ret;
|
||
}
|
||
//计算
|
||
double cal(double a, double b, char ch) {
|
||
if (ch == '+') return a + b;
|
||
if (ch == '-') return a - b;
|
||
if (ch == '*') return a * b;
|
||
if (ch == '%') return (int) ((int) a % (int) b);
|
||
if (ch == '/') {
|
||
if (b != 0) return a / b;
|
||
return 0;
|
||
}
|
||
return 0;
|
||
}
|
||
//中缀表达式转变后缀表达式
|
||
string get_postfix(string s) {
|
||
while (!op.empty()) op.pop();
|
||
op.push('#');
|
||
string ret = "";
|
||
int len = s.length(), i = 0;
|
||
while (i < len) {
|
||
if (s[i] == ' ' || s[i] == '=') {
|
||
i++;
|
||
continue;
|
||
} else if (s[i] == '(') {
|
||
op.push(s[i++]);
|
||
} else if (s[i] == ')') {
|
||
while (op.top() != '(') {
|
||
ret += op.top();
|
||
ret += ' ';
|
||
op.pop();
|
||
}
|
||
op.pop();
|
||
i++;
|
||
} else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '%') {
|
||
while (prior(op.top()) >= prior(s[i])) {
|
||
ret += op.top();
|
||
ret += ' ';
|
||
op.pop();
|
||
}
|
||
op.push(s[i++]);
|
||
} else {
|
||
while (is_digit(s[i]) || s[i] == '.') {
|
||
ret += s[i++];
|
||
}
|
||
ret += ' ';
|
||
}
|
||
}
|
||
while (op.top() != '#') {
|
||
ret += op.top();
|
||
ret += ' ';
|
||
op.pop();
|
||
}
|
||
ret += '=';
|
||
return ret;
|
||
}
|
||
//计算后缀表达式
|
||
double solve(string str) {
|
||
string s = get_postfix(str);
|
||
while (!num.empty()) num.pop();
|
||
int len = s.length(), i = 0;
|
||
while (i < len) {
|
||
if (s[i] == ' ' || s[i] == '=') {
|
||
i++;
|
||
continue;
|
||
} else if (s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/' || s[i] == '%') {
|
||
double a = num.top();
|
||
num.pop();
|
||
double b = num.top();
|
||
num.pop();
|
||
num.push(cal(b, a, s[i]));
|
||
i++;
|
||
} else {
|
||
double x = 0;
|
||
while (is_digit(s[i])) {
|
||
x = x * 10 + s[i] - '0';
|
||
i++;
|
||
}
|
||
if (s[i] == '.') {
|
||
double k = 10.0, y = 0;
|
||
i++;
|
||
while (is_digit(s[i])) {
|
||
y += ((s[i] - '0') / k);
|
||
i++;
|
||
k *= 10;
|
||
}
|
||
x += y;
|
||
}
|
||
num.push(x);
|
||
}
|
||
}
|
||
return num.top();
|
||
}
|
||
} E;
|
||
|
||
typedef struct BT {
|
||
char op;
|
||
double data;
|
||
BT *lch, *rch;
|
||
} node, *btree;
|
||
|
||
void print(btree p) {
|
||
if (!(p->lch) && !(p->rch)) {
|
||
cout << fixed << setprecision(1) << p->data << " ";
|
||
} else cout << p->op << " ";
|
||
}
|
||
|
||
int i;
|
||
|
||
double get_num(string s) {
|
||
double x = 0;
|
||
while (is_digit(s[i])) {
|
||
x = x * 10 + s[i] - '0';
|
||
i++;
|
||
}
|
||
if (s[i] == '.') {
|
||
double k = 10.0, y = 0;
|
||
i++;
|
||
while (is_digit(s[i])) {
|
||
y += ((s[i] - '0') / k);
|
||
i++;
|
||
k *= 10;
|
||
}
|
||
x += y;
|
||
}
|
||
return x;
|
||
}
|
||
|
||
void create(btree &T, string s) {
|
||
T = new node;
|
||
while (i < s.length() && (s[i] == ' ' || s[i] == '.')) i++;
|
||
if (i >= s.length()) {
|
||
T->lch = T->rch = NULL;
|
||
return;
|
||
}
|
||
if (is_digit(s[i])) {
|
||
T->data = get_num(s);
|
||
T->lch = T->rch = NULL;
|
||
i++;
|
||
return;
|
||
} else {
|
||
T->op = s[i];
|
||
i += 2;
|
||
create(T->lch, s);
|
||
create(T->rch, s);
|
||
}
|
||
}
|
||
|
||
void pre_order(btree T) { //前序遍历
|
||
if (T != NULL) {
|
||
print(T);
|
||
pre_order(T->lch);
|
||
pre_order(T->rch);
|
||
}
|
||
}
|
||
|
||
void in_order(btree T) { //中序遍历
|
||
if (T != NULL) {
|
||
in_order(T->lch);
|
||
print(T);
|
||
in_order(T->rch);
|
||
}
|
||
}
|
||
|
||
void post_order(btree T) { //后序遍历
|
||
if (T != NULL) {
|
||
post_order(T->lch);
|
||
post_order(T->rch);
|
||
print(T);
|
||
}
|
||
}
|
||
|
||
double cal_tree(btree &T) {
|
||
if (T != NULL) {
|
||
if (!(T->lch) && !(T->rch)) {
|
||
return T->data;
|
||
} else return E.cal(cal_tree(T->lch), cal_tree(T->rch), T->op);
|
||
}
|
||
}
|
||
|
||
int main() {
|
||
int T;
|
||
cin >> T;
|
||
string str;
|
||
getline(cin, str);
|
||
while (T--) {
|
||
getline(cin, str);
|
||
string pre = E.get_prefix(str), post = E.get_postfix(str);
|
||
cout << "前缀表达式:" << pre << endl;
|
||
cout << "后缀表达式:" << post << endl;
|
||
|
||
btree tree;
|
||
i = 0; //全局变量记录string下标,递归建立表达式树
|
||
create(tree, pre);
|
||
cout << "前序遍历:";
|
||
pre_order(tree);
|
||
cout << endl;
|
||
cout << "中序遍历:";
|
||
in_order(tree);
|
||
cout << endl;
|
||
cout << "后序遍历:";
|
||
post_order(tree);
|
||
cout << endl;
|
||
cout << "后缀表达式计算结果:" << fixed << setprecision(6) << E.solve(str) << endl;
|
||
cout << "表达式树结果:" << fixed << setprecision(6) << cal_tree(tree) << endl << endl;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
/*
|
||
测试样例:
|
||
1000
|
||
1 + 2
|
||
1 + 2 - 3 / 4 * 5
|
||
1 + 2 * (3 - 4) - 5 / 6
|
||
1+2*3-4/(5-6*7+8)/9
|
||
1-2+3*4%(5+6-7/8)+9
|
||
1+(2-3)*4*(5-6+7/8)/9
|
||
11+(22-33)*44*(55-6+7/8)/9
|
||
19+(28-37)*46*(55-64+73/82)/91
|
||
1.2+(2.421-3.3123)*4.0*(5.42342-6+7.2*8.13)/9.1321
|
||
*/ |