表示式·表示式樹·表示式求值 數算mooc C++
阿新 • • 發佈:2018-12-20
表示式·表示式樹·表示式求值
題目內容:
眾所周知,任何一個表示式,都可以用一棵表示式樹來表示。例如,表示式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; }
有疑問隨時交流