一個算術表達式的計算語義可以用二叉樹唯一的表示出來。假設算術表達式的語義二叉樹已經給出,請編碼實現算術表達式的中綴形式(保持計算語義)的輸出,並計算出該表達式的值。
要求:
1)使用二叉樹的完全前序序列建立表達式的語義二叉樹,空子樹用符號@表示;
2)算術運算符包括:+, -, *, / ; 運算量只考慮單數字字符(1位整數)
3 ) 輸出時用括號該表優先級;
提示:
1)遞歸執行下列步驟即可求值:先分別求出左子樹和右子樹表示的子表達式的值,最後根據根結點的運算符的要求,計算出表達式的最後結果。
2)二叉樹的中序遍歷序列與原算術表達式基本相同,但是需要將中序序列加上括號,即當根結點運算符優先級高於左子樹(或右子樹)根結點運算符時,就需要加括號。
例如:
輸入:*2@@-3@@1@@
輸出:2*(3-1)=4
例如:
輸入:
*2@@-3@@1@@
Result:
2*(3-1)=4
思路:
1)輸出表達式:
依題目要求先由完全先序序列建樹,然後通過中序遍歷輸出中綴表達式,難點是判斷什麼時候輸出括號,當根節點的優先級大於其兒子節點的優先級時需要輸出括號,但是注意若是根節點是’-’,左子樹無論是什麼符號都不用輸出括號。否則會出現(5+6)-(7+8)的情況(詳見下面用例)
2)求值:
直接由樹的後序遍歷可以得到後綴表達式,然後就可以直接根據後綴表達式求值。
測試用例:
/+1@@/3@@4@@-+5@@6@@+7@@8@@
(1+3/4)/(5+6-(7+8))=-0.4375
*+1@@/3@@4@@-+5@@6@@+7@@8@@
(1+3/4)*(5+6-(7+8))=-7
-+1@@/3@@4@@-+5@@6@@+7@@8@@
1+3/4-(5+6-(7+8))=5.75
+-*1@@2@@-3@@4@@/+5@@6@@*7@@8@@
1*2-(3-4)+(5+6)/(7*8)=3.19643
-2@@-+2@@1@@1@@
2-(2+1-1)=0
#include <iostream>
#include <cstdio>
#include <queue>
#include <stack>
#include <cstring>
#include <cstdlib>
using namespace std;
struct node
{
char x;
node* lson;
node* rson;
};
void creat(node* &root)///完全先序序列建樹
{
root=new node;
char c;
cin>>c;
if(c=='@') root=NULL;
else
{
root->x=c;
creat(root->lson);
creat(root->rson);
}
}
bool judge(char c)///判斷是否爲運算符
{
if(c=='*'||c=='/'||c=='-'||c=='+')return true;
return false;
}
bool check(char op1,char op2,int lr)///判斷優先級,增添子樹判斷
{
if(lr==1&&op2=='-') ///若爲左子樹,且其父親爲'-',則其優先級一定大於父親的優先級,不需要加()
return false;
if((op1=='+'||op1=='-')&&(op2=='*'||op2=='/'||op2=='-'))
return true;
if((op1=='*'&&op2=='/')||(op1=='/'&&op2=='/'))
return true;
return false;
}
int cnt=0;
char str[1000];
void print(node *root,char op,int lr)///op爲其雙親節點的符號,lr爲左右子樹的判斷標準,
{
if(root==NULL) return;
if(judge(root->x)&&check(root->x,op,lr))///根的優先級大,輸出'('
cout<<'(';
print(root->lson,root->x,1);///左子樹遞歸
cout<<root->x;///輸出中綴表達式
print(root->rson,root->x,2);///右子樹遞歸
if(judge(root->x)&&check(root->x,op,lr))///根的優先級大,輸出')'
cout<<')';
str[cnt++]=root->x;///獲取後綴表達式
}
double cal(char op,double num1,double num)///計算
{
if(op=='+') return num1+num;
if(op=='-') return num1-num;
if(op=='*') return num1*num;
if(op=='/') return num1/num;
}
stack<double> sta;
void getans()///後續表達式求值,利用棧計算
{
int len=strlen(str);
for(int i=0;i<len;i++)
{
if(isdigit(str[i]))
sta.push(str[i]-'0');
else
{
if(!sta.empty())
{
double temp1=sta.top();
sta.pop();
double temp2=sta.top();
sta.pop();
sta.push(cal(str[i],temp2,temp1));
}
}
}
}
int main()
{
node *root;
creat(root);
print(root,'.',0);
cout<<'=';
getans();
printf("%.5lf\n",sta.top());
return 0;
}