表达式·表达式树·表达式求值 数算mooc C++


                                   表达式·表达式树·表达式求值


题目内容:

众所周知,任何一个表达式,都可以用一棵表达式树来表示。例如,表达式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;
}

有疑问随时交流

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值