衆所周知,任何一個表達式,均可以用一棵表達式樹來表示。例如,表達式a+b*c,能夠表示爲以下的表達式樹:
+
/ \
a *
/ \
b c
如今,給你一箇中綴表達式,這個中綴表達式用變量來表示(不含數字),請你將這個中綴表達式用表達式二叉樹的形式輸出出來。ios
輸入分爲三個部分。
第一部分爲一行,即中綴表達式(長度不大於50)。中綴表達式可能含有小寫字母表明變量(a-z),也可能含有運算符(+、-、*、/、小括號),不含有數字,也不含有空格。
第二部分爲一個整數n(n < 10),表示中綴表達式的變量數。
第三部分有n行,每行格式爲C x,C爲變量的字符,x爲該變量的值。express
輸出分爲三個部分,第一個部分爲該表達式的逆波蘭式,即該表達式樹的後根遍歷結果。佔一行。
第二部分爲表達式樹的顯示,如樣例輸出所示。若是該二叉樹是一棵滿二叉樹,則最底部的葉子結點,分別佔據橫座標的第一、三、五、7……個位置(最左邊的座標是1),而後它們的父結點的橫座標,在兩個子結點的中間。若是不是滿二叉樹,則沒有結點的地方,用空格填充(但請略去全部的行末空格)。每一行父結點與子結點中隔開一行,用斜槓(/)與反斜槓(\)來表示樹的關係。/出現的橫座標位置爲父結點的橫座標偏左一格,\出現的橫座標位置爲父結點的橫座標偏右一格。也就是說,若是樹高爲m,則輸出就有2m-1行。
第三部分爲一個整數,表示將值代入變量以後,該中綴表達式的值。須要注意的一點是,除法表明整除運算,即捨棄小數點後的部分。同時,測試數據保證不會出現除以0的現象。數組
a+b*c
3
a 2
b 7
c 5函數
abc*+
+
/ \
a *
/ \
b c
37測試
因此,構建一個表達式樹,關鍵在於找到表達式的根結點,而後分左右兩個部分構建樹;拓展到多個同級運算符的表達式:\(a+b+c+...+n\),能夠這樣構建其表達式樹:lua
這樣就能夠構建出整個表達式樹:spa
因此,含有優先級不一樣的表達式,關鍵在於找到表達式最後運算的運算符,做爲某個表達式樹的根,而後分左右兩個部分構建樹;一樣,同級運算符以最左邊的運算符爲最後運算的運算符,統一第一種狀況:拓展到多個不一樣運算符出現的狀況:\(a+b*c p_1...p_k n(p_i爲第i個運算符)\).net
這樣就能夠構建出整個表達式樹:指針
因此,構建表達式樹的函數:CreateExpressionTree(char *expression, int start, int end, Bitree &tree)
中,傳入了表達式的開始下標和結尾下標,方便分割左邊和右邊部分:
CreateExpressionTree(char *expression, int start, int end, Bitree &tree)
函數:code
void CreateExpressionTree(char *expression, int start, int end, Bitree &tree) { /** * 這裏,c1用來記錄括號外最後運算的+或- * c2用來記錄括號外最後運算的+或- * p記錄括號當讀到一個( p++, ) 時 p--, 只有p==0時才說明c1, c2 * 括號外 */ int i, c1 = -1, c2 = -1, p = 0; if (end - start == 1) { //只有一個結點,直接創建結點 tree = new BTNode; tree->data = *(expression+start); tree->left_child = tree->right_child = NULL; return; } for (i = start; i < end; i++) { switch (*(expression+i)) { case '(': p++; break; case ')': p--; break; case '+': case '-': if (!p) c1 = i; break; case '*': case '/': if (!p) c2 = i; break; } } //c1 < 0,說明括號外沒有第一優先級的+或者-,那麼就只能考慮*或者/ if (c1 < 0) c1 = c2; // 說明括號外沒有第一優先級的*或者/,說明此時表達式被括號括起來, 去掉括號後建樹 if (c1 < 0) CreateExpressionTree(expression,start+1,end-1,tree); else { //創建根 CreateExpressionTree(expression,c1,c1 + 1,tree); //創建左樹 CreateExpressionTree(expression,start,c1,tree->left_child); //創建右樹 CreateExpressionTree(expression,c1+1,end,tree->right_child); } }
如題:
若是該二叉樹是一棵滿二叉樹,則最底部的葉子結點,分別佔據橫座標的第一、三、五、7……個位置(最左邊的座標是1),而後它們的父結點的橫座標,在兩個子結點的中間。若是不是滿二叉樹,則沒有結點的地方,用空格填充(但請略去全部的行末空格)。每一行父結點與子結點中隔開一行,用斜槓(/)與反斜槓(\)來表示樹的關係。/出現的橫座標位置爲父結點的橫座標偏左一格,\出現的橫座標位置爲父結點的橫座標偏右一格。也就是說,若是樹高爲m,則輸出就有2m-1行。
用一個graph[MAX_ROW][MAX_COL] 數組保存表達式樹的位置信息。以題例來看:
+
/ \
a *
/ \
b c
首先,一共有\(2^h-1\)個結點,層層找結點位置,中間位置,即第\(2^{h-1}\)個結點+把該層分爲兩個部分,且左右部分皆是\(2^{h-2}\)長度(ps:由於包含了\/的位置),若是有左結點,左結點就在\(2^{h-2}\)的中間部分,(ps:這裏因爲用到了\(2^x\)次方,在宏定義了一個POW(NUM) 1 << NUM, 1 << NUM 即右移NUM,即\(2^{NUM}\))右結點也如此處理...這樣,處理下一層時,也如同上一層處理:先處理根結點,在處理左右結點。在處理完根結點後下一層應該留給/\,位置爲中間位置左偏一個或右偏一個;
void Print(Bitree root, int row, int col, int len) { if (root == NULL) return; graph[row][col-1] = root->data; //當前層中間位置 if (root->left_child!=NULL) { graph[row+1][col-2] = '/'; //下一層留給/,中間位置偏左一個 Print(root->left_child,row+2,col-len,len>>1); // 左邊部分 } if (root->right_child!=NULL) { graph[row+1][col] = '\\'; Print(root->right_child,row+2,col+len,len>>1); } }
對於這一部分,因爲已經有了表達式樹了,只須要一層層求解便可:
其餘部分根據題意求解便可,關於表達式輸入,使用了一個char*指針,可是我在這個地方初始化 expression = new char [52];
一開始記成 expression = new char (52);
致使一直不能過...
/* @File : expression_tree.cpp @Time : 2020/04/27 @Desc : 表達式·表達式樹·表達式求值 */ #include <iostream> #include <stdlib.h> #include <string.h> #include <math.h> #include <map> #define POW(NUM) 1<<NUM #define MAX_ROW 70 #define MAX_COL 300 using namespace std; typedef struct BTNode { char data; struct BTNode *left_child; struct BTNode *right_child; }*Bitree; char graph[MAX_ROW][MAX_COL]; map <char,int> to_value; void CreateExpressionTree(char *expression, int start, int end, Bitree &tree) { int i, c1 = -1, c2 = -1, p = 0; if (end - start == 1) { tree = new BTNode; tree->data = *(expression+start); tree->left_child = tree->right_child = NULL; return; } for (i = start; i < end; i++) { switch (*(expression+i)) { case '(': p++; break; case ')': p--; break; case '+': case '-': if (!p) c1 = i; break; case '*': case '/': if (!p) c2 = i; break; } } if (c1 < 0) c1 = c2; if (c1 < 0) CreateExpressionTree(expression,start+1,end-1,tree); else { CreateExpressionTree(expression,c1,c1 + 1,tree); CreateExpressionTree(expression,start,c1,tree->left_child); CreateExpressionTree(expression,c1+1,end,tree->right_child); } } void PostOrder(Bitree tree) { if (tree == NULL) return; PostOrder(tree->left_child); PostOrder(tree->right_child); cout << tree->data; } int GetHeight(Bitree tree) { int left_height, right_height; if (tree == NULL) return 0; else { left_height = GetHeight(tree->left_child); right_height = GetHeight(tree->right_child); return (left_height > right_height)?(left_height+1):(right_height+1); } } void Print(Bitree root, int row, int col, int len) { if (root == NULL) return; graph[row][col-1] = root->data; if (root->left_child!=NULL) { graph[row+1][col-2] = '/'; Print(root->left_child,row+2,col-len,len>>1); } if (root->right_child!=NULL) { graph[row+1][col] = '\\'; Print(root->right_child,row+2,col+len,len>>1); } } int Calculate(Bitree tree) { switch (tree->data) { case '+': return Calculate(tree->left_child) + Calculate (tree->right_child); break; case '-': return Calculate(tree->left_child) - Calculate (tree->right_child); break; case '*': return Calculate(tree->left_child) * Calculate (tree->right_child); break; case '/': return Calculate(tree->left_child) / Calculate (tree->right_child); break; default: return to_value[tree->data]; break; } } int main(int argc, char const *argv[]) { int n, value; char *expression, valuable; Bitree tree; // expression = (char*)malloc(sizeof(char)*52); // expression = new char(52); !!!!! expression = new char[52]; cin >> expression; cin >> n; while (n--) { cin >> valuable >> value; to_value[valuable] = value; } CreateExpressionTree(expression,0,strlen(expression),tree); PostOrder(tree); cout << endl; memset(graph,' ',sizeof(graph)); Print(tree,0,POW(GetHeight(tree)-1),POW(GetHeight(tree)-2)); int j = 0, l = 0; for (int i = 0; i < MAX_ROW; ++i) { j = MAX_COL - 1; while (j >= 0 && graph[i][j] == ' ') --j; if (j > -1) { ++l; graph[i][j+1] = '\0'; } else break; } for (int i = 0; i < l; ++i) cout << graph[i] << endl; cout << Calculate(tree) << endl; system("pause"); return 0; }