中綴表達式生成二叉樹


中綴表達式生成二叉樹,大概應該有遞規,迭代,和編譯原理中的自頂向下的預測分析法等。

遞規,迭代的思路每次讀出一個數字,一個運算符,比較當前運算符和之前符號的優先級,進行相關的操作。

自頂向下的預測分析法,做了下,實在忘記的差不多了,先占個位。以后完成。

 

tree.c

#include "head.h"



struct Node * CreateNodesetV(int number,char opr,int type)
{
    struct nodeData db;
    db.numberValue=number;
    db.operatorValue=opr;
    db.symbolType=type;

    struct Node * myNode=malloc(sizeof(struct Node));

    CreateNode(db,myNode);
    return myNode;
};


void  CreateNode(struct nodeData nd,struct Node * myN)
{
    myN->NData.numberValue=nd.numberValue;
    myN->NData.operatorValue=nd.operatorValue;
    myN->NData.symbolType=nd.symbolType;

    myN->lchilden='\0';
    myN->rchilden='\0';
};



char insertNode(struct Node * myNode,struct Node * father,char lr)
{
    char result='Y';
    if(lr=='L')
    {
        if(father->lchilden=='\0')
        {
            father->lchilden=myNode;
        }
        else
        {
            result='N';
        }

    }
    else
    {
        if(father->rchilden=='\0')
        {
            father->rchilden=myNode;
        }
        else
        {
            result='N';
        }
    }

    return result;
}

//原來樹的遍歷也就是遞歸.我去,我說自己怎么老是不得要領.根源在於沒想明白遞歸函數.
void visitTree(struct Node * Root)
{
    if(Root->lchilden!='\0')
    {
        visitTree(Root->lchilden);
    }
    else
    {
        //終止遞歸的確定事件,是無事件.
    }


    if(Root->NData.symbolType==1)
    {
        printf("%d",Root->NData.numberValue);
    }
    else
    {
        printf("%c",Root->NData.operatorValue);
    }


    if(Root->rchilden!='\0')
    {
        visitTree(Root->rchilden);
    }
    else
    {
        //終止遞歸的確定事件,是無事件.
    }
}


//所以如果用遞歸來做運算必須是后序遍歷,要等左右樹都有結果了,才用符號。 //其實我們的心算和筆算,也是后續遍歷。 int visitTree_2(struct Node * Root) { int lvalue; int rvalue; int result; if(Root->lchilden!='\0') { lvalue=visitTree_2(Root->lchilden); } else { return Root->NData.numberValue; } if(Root->rchilden!='\0') { rvalue=visitTree_2(Root->rchilden); } else { return Root->NData.numberValue; } switch (Root->NData.operatorValue) { case '+': { result=lvalue+rvalue; break; } case '-': { result=lvalue-rvalue; break; } case '*': { result=lvalue*rvalue; break; } case '/': { result=lvalue/rvalue; break; } } return result; }

 

head.h

 

//tree

struct nodeData
{
    int symbolType; //1: number 2: operator
    int numberValue;
    char operatorValue;
};

struct Node
{
    struct nodeData NData;
    struct Node * lchilden;
    struct Node * rchilden;
};


char insertNode(struct Node * myNode,struct Node * father,char lr);
struct Node * CreateNodesetV(int number,char opr,int type);
void  CreateNode(struct nodeData nd,struct Node * myN);
void visitTree(struct Node * Root);

 

1)迭代方法

main.c

  基本思路就是我們手工畫圖的步驟。寫成代碼而已。

 每次取一個數字和操作符,對比操作符和之前操作符的優先順序。
    狀1,大於,則符號為之前樹的右子樹,數字為符號的左子樹。
    狀2,小於,則數字為之前樹的右字樹,之前樹為符號的左子樹。
直至最后,只有一個數字符,此數字為之前符號的右子樹,
int main()
{
    char * expression="2+3*5-4/2";

    //每次取一個數字和操作符,對比操作符和之前操作符的優先順序。
    //狀1,大於,則符號為之前樹的右子樹,數字為符號的左子樹。
    //狀2,小於,則數字為之前樹的右字樹,之前樹為符號的左子樹。
    //直至最后,只有一個數字符,此數字為之前符號的右子樹,

    char preOpe='#';
    struct Node * PreNode='\0';
    struct Node * RootNode='\0';
    int i=0;
    int strLen=getStrLen(expression);
    while(i<strLen)
    {
        if(i==0)//
        {
            int cNumber=expression[i]-48;
            i++;
            char cOperator=expression[i];
            i++;
            struct Node * LeftC=CreateNodesetV(cNumber,' ',1);
            struct Node * Root=CreateNodesetV(0,cOperator,2);
            insertNode(LeftC,Root,'L');
            preOpe=cOperator;
            PreNode=Root;
            RootNode=Root;
        }
        else
        {
            if(i+2<strLen)//get a number and operator
            {
                int cNumber=expression[i]-48;
                i++;
                char cOperator=expression[i];
                i++;
                if(lHeight(preOpe,cOperator)==1)
                {
                    struct Node * numberNode=CreateNodesetV(cNumber,' ',1);
                    struct Node * OpeNode=CreateNodesetV(0,cOperator,2);
                    insertNode(OpeNode,PreNode,'R');
                    insertNode(numberNode,OpeNode,'L');
                    preOpe=cOperator;
                    PreNode=OpeNode;
                }
                else if (lHeight(preOpe,cOperator)==0)
                {
                    struct Node * numberNode=CreateNodesetV(cNumber,' ',1);
                    struct Node * OpeNode=CreateNodesetV(0,cOperator,2);
                    insertNode(RootNode,OpeNode,'L');
                    insertNode(numberNode,PreNode,'R');
                    preOpe=cOperator;
                    PreNode=OpeNode;
                    RootNode=OpeNode;
                }
            }
            else//last char
            {
                int cNumber=expression[i]-48;
                i++;
                struct Node * numberNode=CreateNodesetV(cNumber,' ',1);
                insertNode(numberNode,PreNode,'R');
            }
        }
    }

    if(RootNode!='\0')
    {
        visitTree(RootNode);
        printf("\nresult:%d",visitTree_2(RootNode));
    }

    return 0;
}

int getStrLen(char * c)
{
    int i=0;
    while(c[i]!='\0')
    {
        i++;
    }
    return i;
}

int lHeight(char oldc,char newl)
{
    if(oldc=='+'||oldc=='-')
    {
        if(newl=='*'||newl=='/')
        {
            return 1;
        }
    }
    else if(oldc=='#')
    {
        return 1;
    }
    return 0;
}

 

2) 遞規方式。

     尾遞規一般是可以用循環迭代來表示。所以這里遞規其實並不是很體現優勢。

  只是可以鍛煉下遞規的思路,遞規是:把問題難度逐層降低,以至到達某個層次(一般0或1),是個確定的操作不需要遞規,那么這個層次的上層的操作也變成了確定操作。以至最終解決問題。

  這里一樣的思路:一個表達式很長,我只能解決一個數字,一個操作符,並把他放到之前的樹上。剩下的表達式也就是遺留的問題讓下層去做。下層能做的事和上面一樣。以至到最后,只剩下一個數字,只能防到右葉,遺留的問題,到這里終結。

mian.c

void CreateTree(char * expression,struct Node * PreNode,char preOpe);
struct Node * Root='\0';
int main()
{
    char * expression="2+3*5-4/2";
    char preOpe='#';
    struct Node * PreNode='\0';
    int strLen=getStrLen(expression);

    CreateTree(expression,PreNode,preOpe);

    if(Root!='\0')
    {
        visitTree(Root);
        printf("\nresult:%d",visitTree_2(Root));
    }

    return 0;
}

void CreateTree(char * expression,struct Node * PreNode,char preOpe)
{
    int strLen=getStrLen(expression);
    if(strLen>1)
    {
        int cNumber=expression[0]-48;
        char cOperator=expression[1];
        if(lHeight(preOpe,cOperator)==1)
        {
            struct Node * numberNode=CreateNodesetV(cNumber,' ',1);
            struct Node * OpeNode=CreateNodesetV(0,cOperator,2);
            if(preOpe!='#')
            {
                insertNode(OpeNode,PreNode,'R');
                insertNode(numberNode,OpeNode,'L');
                preOpe=cOperator;
                PreNode=OpeNode;
            }
            else
            {
                insertNode(numberNode,OpeNode,'L');
                preOpe=cOperator;
                PreNode=OpeNode;
                Root=OpeNode;
            }
        }
        else if (lHeight(preOpe,cOperator)==0)
        {
            struct Node * numberNode=CreateNodesetV(cNumber,' ',1);
            struct Node * OpeNode=CreateNodesetV(0,cOperator,2);
            insertNode(Root,OpeNode,'L');
            insertNode(numberNode,PreNode,'R');
            preOpe=cOperator;
            PreNode=OpeNode;
            Root=OpeNode;
        }

        CreateTree(expression+2,PreNode,preOpe);
    }
    else
    {
        int cNumber=expression[0]-48;
        struct Node * numberNode=CreateNodesetV(cNumber,' ',1);
        insertNode(numberNode,PreNode,'R');
    }
}

3)自頂向下的預測分析。

    做了下,沒出來。以后看看。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM