总结了一下常见的表达式求值问题,写了一个模板,输入为中缀式时,用中缀式建立表达式二叉树,可以打印前缀式和后缀式,可以用前缀式计算,也可以用后缀式计算。
代码如下:
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstdlib>
#include<vector>
#include<climits>
#include<ctime>
#include<stack>
#include<algorithm>
using namespace std;
#define MAX 1005
#define CLR(arr, what) memset(arr, what, sizeof(arr))
struct Node
{
char ope[10];
Node *lchild, *rchild;
Node()
{
CLR(ope, '\0');
lchild = rchild = NULL;
}
};
class Exp
{
private:
Node *root;
int prelen, postlen; //前缀式长度、后缀式长度
int pos; //前缀式计算指针
char str[MAX], pre[MAX], post[MAX]; //中缀式、前缀式、后缀式
stack<double> num; //后缀式计算->数字栈
double answer;
public:
Exp(char[]); //构造函数
Node* Build_Exp(int start, int end); //建表达式树
void Pre_Order(Node*); //前缀式遍历
void Post_Order(Node*); //后缀式遍历
void PreOut(){cout<<pre<<"="<<endl;} //输出前缀式
void PostOut(){cout<<post<<"="<<endl;} //输出后缀式
double Pre_Calucate(); //前缀式计算
double Post_Calucate(); //后缀式计算
double result(); //输出结果
void clear(Node*);
~Exp(){ clear(root);}; //销毁二叉树
};
Exp::Exp(char s[])
{
root = new Node;
pos = -1;
prelen = 0, postlen = 0;
CLR(str, '\0'); CLR(pre, '\0'), CLR(post, '\0');
while(!num.empty())
num.pop();
strcpy(str, s);
root = Build_Exp(0, strlen(str) - 2); //中缀式长度可按题目改变~
}
Node* Exp::Build_Exp(int src, int des)
{
if(src > des)
return 0;
if(str[src] >= '0' && str[src] <= '9' || str[src] == '.')
{
double temp;
int length;
sscanf(&str[src], "%lf%n", &temp, &length);
if(src + length -1 == des)
{
Node* cur = new Node;
sprintf(cur->ope, "%lf", temp);
cur->ope[length] = '\0';
cur->lchild = NULL, cur->rchild = NULL;
return cur;
}
}
int optr1 = -1, optr2 = -1, pos = 0; // +- || ×/
for(int i = src; i <= des; ++i) //寻找树根
{
switch(str[i])
{
case '(': pos++; break;
case ')': pos--; break;
case '+':
case '-': if(pos == 0) optr1 = i; break;
case '*':
case '/': if(pos == 0) optr2 = i; break;
}
}
if(optr1 < 0)
optr1 = optr2;
if(optr1 < 0)
return Build_Exp(src + 1, des - 1); //被括号包围
Node* upper = new Node;
upper->ope[0] = str[optr1];
upper->ope[1] = '\0';
upper->lchild = Build_Exp(src, optr1 - 1); //递归建左子树
upper->rchild = Build_Exp(optr1 + 1, des); //递归建右子树
return upper;
}
void Exp::Pre_Order(Node* rot)
{
if(rot != NULL)
{
sprintf(&pre[prelen], "%s", rot->ope);
prelen += strlen(rot->ope);
pre[prelen++] = ' ';
Pre_Order(rot->lchild);
Pre_Order(rot->rchild);
}
}
void Exp::Post_Order(Node* rot)
{
if(rot != NULL)
{
Post_Order(rot->lchild);
Post_Order(rot->rchild);
sprintf(&post[postlen], "%s", rot->ope);
postlen += strlen(rot->ope);
post[postlen++] = ' ';
}
}
double Exp::Pre_Calucate()
{
pos++;
if(pre[pos] == ' ') pos++;
if(pre[pos] >= '0' && pre[pos] <= '9')
{
double temp;
int length;
sscanf(&pre[pos], "%lf%n", &temp, &length);
pos += length - 1;
return temp;
}
if(pre[pos] == '+')
return Pre_Calucate() + Pre_Calucate();
if(pre[pos] == '-')
return Pre_Calucate() - Pre_Calucate();
if(pre[pos] == '*')
return Pre_Calucate() * Pre_Calucate();
if(pre[pos] == '/')
return Pre_Calucate() / Pre_Calucate();
}
double Exp::Post_Calucate()
{
postlen = strlen(post) - 1; //最后一个是空格
for(int i = 0; i < postlen; ++i)
{
if(post[i] >= '0' && post[i] <= '9') //操作数
{
double temp;
int length;
sscanf(&post[i], "%lf%n", &temp, &length);
i += length - 1;
num.push(temp);
}
else if(post[i] == ' ')
continue;
else//操作符
{
double a, b;
b = num.top(); num.pop();
a = num.top(); num.pop();
switch(post[i])
{
case '+': num.push(a + b); break;
case '-': num.push(a - b); break;
case '*': num.push(a * b); break;
case '/': num.push(a / b); break;
}
}
}
return num.top();
}
double Exp::result()
{
Pre_Order(root);
PreOut();
Post_Order(root);
PostOut();
return Pre_Calucate();
//return Post_Calucate();
}
void Exp::clear(Node* rot)
{
if(rot->lchild != NULL)
clear(rot->lchild);
if(rot->rchild != NULL)
clear(rot->rchild);
delete(rot);
}
int main()
{
int ncase;
scanf("%d", &ncase);
while(ncase--)
{
char s[MAX];
cin>>s;
Exp e(s);
printf("%.2lf\n", e.result());
}
return 0;
}