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.

309 lines
8.6 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;
/**
从后缀表达式建立表达式树
比如现在有以下一个后缀表达式:
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
*/