1. 程式人生 > >表示式·表示式樹·表示式求值 數算mooc C++

表示式·表示式樹·表示式求值 數算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;
}

有疑問隨時交流