/* 簡單中序算術表達式轉爲二叉樹, 至於轉成了二叉樹, 前中後遍歷就隨意了
1. 將表達式轉爲後綴表達式, 然後轉爲二叉樹, 或者用2步驟.
2. 理論上來講, 一箇中綴表達式是不能夠轉換出一個唯一的二叉樹的,
但是中綴算術表達式因爲有運算符的優先級關係, 建立二叉樹時, 需要所有的操作數
都在葉子節點上, 所有的操作符都在父(根)節點上, 這個特徵可以生成一個唯一的二叉樹
3. 原理: 每次找到最後計算的運算符, 然後去遞歸處理, 因爲'*'和'/'的運算符優先級高於
'+', '-', 這樣我們找運算符是應該優先選擇'+','-',然後再考慮'*', '/'.
至於括號, 去掉對括號內的內容作同樣的遞歸分析即可, 中序遍歷的時候注意將括號恢復.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct _tBINARY_TREE_
{
int value;
_tBINARY_TREE_ *lchild;
_tBINARY_TREE_ *rchild;
}tBINARY_TREE;
static int find_split(const char *express, int start, int end)
{
int tag = -1;
if (express[start] == '(' && express[end] == ')')
{
++start;
--end;
}
int is_in_braket = 0;
int more_grade = 0;
for (int i = start; i <= end; i++)
{
if (express[i] == '(')
++is_in_braket;
else if (express[i] == ')')
--is_in_braket;
if ((express[i] == '+' || express[i] == '-')
&& is_in_braket == 0)
{
more_grade = 1;
tag = i; //無break, 找最後一個符合條件的運算符, 取頂級的+和-
}
else if ((express[i] == '*' || express[i] == '/')
&& more_grade == 0
&& is_in_braket == 0)
{
tag = i; //無break, 找最後一個符合條件的運算符
}
}
return tag;
}
static tBINARY_TREE *do_create_binary_tree(const char *express, int start, int end)
{
tBINARY_TREE *pTree = NULL;
if (start == end)
{
pTree = new tBINARY_TREE;
pTree->value = express[start];
pTree->lchild = NULL;
pTree->rchild = NULL;
}
else
{ //遞歸調用, 各自創建左右的表達式的對應二叉樹
int tag = find_split(express, start, end);
if (tag < 0)
{
printf("1.invalid express, exit.\n");
exit(-1);
}
else
{
pTree = new tBINARY_TREE;
pTree->value = express[tag];
}
if (express[start] == '(' && express[end] == ')')
{
++start;
--end;
}
pTree->lchild = do_create_binary_tree(express, start, tag-1);
pTree->rchild = do_create_binary_tree(express, tag+1, end);
}
return pTree;
}
static tBINARY_TREE *create_binary_tree(const char *infix_express)
{
return do_create_binary_tree(infix_express, 0, strlen(infix_express)-1);
}
static int priority_com(int operator1, int operator2)
{
if (operator1 == '*' || operator1 == '/')
{
if (operator2 == '+' || operator2 == '-')
return 1;
}
return 0;
}
//遞歸中序遍歷二叉樹, 需要注意將括號恢復
static void in_order_traverser(tBINARY_TREE *pTree)
{
int flag_l = 0, flag_r = 0;
if (pTree != NULL)
{
int ret;
if (pTree->lchild != NULL) //非葉子節點
{
ret = priority_com(pTree->value, pTree->lchild->value);
if (ret < 0)
{
printf("2. invalid express, exit.\n");
exit(-1);
}
else if (ret == 1) //當前節點的優先級大於左子樹, 左子樹需要加括號, 防止誤解
{
printf("%c", '(');
flag_l = 1;
}
}
in_order_traverser(pTree->lchild);
if (flag_l == 1)
{
printf("%c", ')');
flag_l = 0;
}
printf("%c", pTree->value);
if (pTree->rchild != NULL) //非葉子結點
{
ret = priority_com(pTree->value, pTree->rchild->value);
if (ret < 0)
{
printf("3. invalid express, exit.");
exit(-1);
}
else if (ret == 1)//當前節點的優先級大於右子樹, 又子樹需要加括號, 防誤解
{
printf("%c", '(');
flag_r = 1;
}
}
in_order_traverser(pTree->rchild);
if (flag_r == 1)
{
printf("%c", ')');
flag_r = 0;
}
}
}
//遞歸先序遍歷二叉樹
static void pre_order_traverser(tBINARY_TREE *pTree)
{
if (pTree != NULL)
{
printf("%c", pTree->value);
pre_order_traverser(pTree->lchild);
pre_order_traverser(pTree->rchild);
}
}
//遞歸後序遍歷二叉樹
static void post_order_traverser(tBINARY_TREE *pTree)
{
if (pTree != NULL)
{
post_order_traverser(pTree->lchild);
post_order_traverser(pTree->rchild);
printf("%c", pTree->value);
}
}
static void destroy_binary_tree(tBINARY_TREE *pTree)
{
if (pTree != NULL)
{
destroy_binary_tree(pTree->lchild);
destroy_binary_tree(pTree->rchild);
delete pTree; pTree = NULL;
}
}
int main(void)
{
const char express[] = "a+b*c+((d*e)+f)*g";
//const char express[] = "a*(b-c)";
//const char express[] = "((a+b)*c+d)*e*f+(g-h)*m";
tBINARY_TREE *pTree = create_binary_tree(express);
if (pTree != NULL)
{
printf("prefix order:\n");
pre_order_traverser(pTree);
printf("\n\ninfix order:\n");
in_order_traverser(pTree);
printf("\n\npostfix order:\n");
post_order_traverser(pTree);
printf("\n");
destroy_binary_tree(pTree);
}
return 0;
}
簡單中序算術表達式直接建立二叉樹測試
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.