表达式·表达式树·表达式求值
题目内容:
众所周知,任何一个表达式,都可以用一棵表达式树来表示。例如,表达式a+b*c,可以表示为如下的表达式树:
+
/ \
a *
/ \
b c
现在,给你一个中缀表达式,这个中缀表达式用变量来表示(不含数字),请你将这个中缀表达式用表达式二叉树的形式输出出来。
输入格式:
输入分为三个部分。
第一部分为一行,即中缀表达式(长度不大于50)。中缀表达式可能含有小写字母代表变量(a-z),也可能含有运算符(+、-、*、/、小括号),不含有数字,也不含有空格。
第二部分为一个整数n(n < 10),表示中缀表达式的变量数。
第三部分有n行,每行格式为C x,C为变量的字符,x为该变量的值。
输出格式:
输出分为三个部分,第一个部分为该表达式的逆波兰式,即该表达式树的后根遍历结果。占一行。
第二部分为表达式树的显示,如样例输出所示。如果该二叉树是一棵满二叉树,则最底部的叶子结点,分别占据横坐标的第1、3、5、7……个位置(最左边的坐标是1),然后它们的父结点的横坐标,在两个子结点的中间。如果不是满二叉树,则没有结点的地方,用空格填充(但请略去所有的行末空格)。每一行父结点与子结点中隔开一行,用斜杠(/)与反斜杠(\)来表示树的关系。/出现的横坐标位置为父结点的横坐标偏左一格,\出现的横坐标位置为父结点的横坐标偏右一格。也就是说,如果树高为m,则输出就有2m-1行。
第三部分为一个整数,表示将值代入变量之后,该中缀表达式的值。需要注意的一点是,除法代表整除运算,即舍弃小数点后的部分。同时,测试数据保证不会出现除以0的现象。
输入样例:
a+b*c 3 a 2 b 7 c 5
输出样例:
abc*+ + / \ a * / \ b c 37
代码如下
#include <iostream>
using namespace std;
#define MAX 63536
#include<cstring>
#include<map>
#include <math.h>
string s;//存放中缀字符串
string postfix;//后缀字符串
map<char, int>m;//map构建字母与数值的对应
char out[50][300];//用来存放要打印的树
#include<stack>
struct node
{
char ch;
node *l,*r;
node()
{
l=r=NULL;
}
} *root;//根节点
//中缀转后缀表达式
void infixToPost( string a)
{
int len = a.size();
stack<char>S;
for (int j = 0; j < len; j++)
{
if (isalpha(a[j])) {postfix += a[j]; }
else if(a[j]=='(')S.push(a[j]);
else if (a[j] == ')')
{
while (!S.empty() && S.top() != '(')
{
postfix += S.top();
S.pop();
}
if (!S.empty())S.pop();
}
else
{
while (!S.empty() && S.top() != '(' && (a[j] == '+' || a[j] == '-' || S.top() == '*' || S.top() == '/'))
{
postfix += S.top();
S.pop();
}
S.push(a[j]);
}
}
while (!S.empty())
{
postfix += S.top();
S.pop();
}
}
int calculate(node *cur)//根据树来计算答案
{
if(isalpha(cur->ch))return m[cur->ch];
else
{
switch(cur->ch)
{
case '+':return calculate(cur->l)+calculate(cur->r);
case '-':return calculate(cur->l)-calculate(cur->r);
case '*':return calculate(cur->l)*calculate(cur->r);
case '/':return calculate(cur->l)/calculate(cur->r);
}
}
}
int find_height(node * cur)//找树的高度
{
if(!cur)return 0;
int l=find_height(cur->l);
int r=find_height(cur->r);
return l>r?l+1:r+1;
}
//根据树将输出内容存放到out字符数组中
void result(node *cur,int x,int y,int space)
{
out[x][y]=cur->ch;
if(cur->l)
{
out[x+1][y-1]='/';
result(cur->l,x+2,y-space,space>>1);
}
if(cur->r)
{
out[x+1][y+1]='\\';
result(cur->r,x+2,y+space,space>>1);
}
}
void build()//建树
{
stack<node *>S;
int count=postfix.size();//根据后根序列来建树
for (int i = 0; i < count; ++i)
{
node * t=new node;
t->ch=postfix[i];
// cout<<t->ch<<endl;
if(!isalpha(t->ch))//如果是运算符,则弹栈
{
t->r=S.top();S.pop();
t->l=S.top();S.pop();
}
S.push(t);//否则将字母压栈
}
root=S.top();S.pop();
}
void print_tree(int dep)//打印树
{
for(int i=0;i<2*dep-1;i++)
{
int j=299;
while(out[i][j]==' ')j--;
out[i][j+1]=0;
// int k=0;
// while(out[i][k]!=0)
// {
// cout<<out[i][k]<<":"<<k;
// k++;
// }
cout<<out[i]<<endl;
}
}
int main(int argc, char const * argv[])
{
//map<char, int>::iterator iter;
int char_n;
getline(cin, s);//读入第一行字符串,存入全局变量s中
cin >> char_n;//读入字符个数
int temp = char_n;
while (temp--)//依次读入字符和对应数值,并存入字典中
{
char c;
int num;
cin >> c >> num;
m[c] = num;
}
// cout << s << endl;
// cout << char_n<<endl;
// for (iter = m.begin(); iter != m.end(); iter++)
// cout << iter->first << " " << iter->second << endl;
infixToPost(s);
cout<<postfix<<endl;//输出后根序列
build();//根据后根序列建树
int height=find_height(root);//树的高度height
memset(out,' ',sizeof(out));//以“ ”来初始out数组
int y=pow(2,height-1)-1;
//y为根节点在result中的位置,因为题目要求叶子节点坐标是从1开始的,所以要减1,就是最前面的“ ”不打印
result(root,0,y,(y+1)>>1);//0是根节点在out中所在层数标号
print_tree(height);
cout<<calculate(root);
return 0;
}
有疑问随时交流