中綴表達式生成二叉樹,大概應該有遞規,迭代,和編譯原理中的自頂向下的預測分析法等。
遞規,迭代的思路每次讀出一個數字,一個運算符,比較當前運算符和之前符號的優先級,進行相關的操作。
自頂向下的預測分析法,做了下,實在忘記的差不多了,先占個位。以后完成。
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)自頂向下的預測分析。
做了下,沒出來。以后看看。