數據結構與算法實驗 實驗7:算術表達式的語義二叉樹 (表達式二叉樹轉化爲中綴表達式,求值)

一個算術表達式的計算語義可以用二叉樹唯一的表示出來。假設算術表達式的語義二叉樹已經給出,請編碼實現算術表達式的中綴形式(保持計算語義)的輸出,並計算出該表達式的值。

要求:

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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章