二叉樹的常見建立和遍歷
阿新 • • 發佈:2018-11-02
#include <stdio.h> #include <stdlib.h>> const int MAX=20; typedef struct Node { char data; struct Node*lchild; struct Node*rchild; }BiTreeNode; //構造二叉樹 //1.按照先序遍歷,利用遞迴構造 //ABD#G##EH##I##CF#J### void CreateBiTree_PreOrder(BiTreeNode **T) //注意傳的是指標的指標 { char ch; scanf("%c",&ch); if('#'==ch) *T=NULL; else { *T=(BiTreeNode*)malloc(sizeof(BiTreeNode)); if(NULL==*T) exit(-1); (*T)->data=ch; CreateBiTree_PreOrder(&(*T)->lchild); CreateBiTree_PreOrder(&(*T)->rchild); } } //BiTreeNode* CreateBiTree_PreOrder(BiTreeNode *T) //傳的指標 //{ // char ch; // scanf("%c",&ch); // if('#'==ch) // T=NULL; // else // { // T=(BiTreeNode*)malloc(sizeof(BiTreeNode)); // if(NULL==T) // exit(-1); // T->data=ch; // T->lchild=T->rchild=NULL; // T->lchild=CreateBiTree_PreOrder(T->lchild); // T->rchild=CreateBiTree_PreOrder(T->rchild); // } // return T; //} //2.按照帶括號的字串構造二叉樹 /* 思路:a(b(c,d),e(f(,g),h(i))) '(':表明已建立的節點為雙親節點,入棧。將要建立左孩子節點,用flag=1標記 ',' :表明將要建立的節點為右孩子節點。用flag=2標記。 ')' :表明左右孩子節點建立和連結完畢,父節點出棧 default:建立節點,並且賦值,判斷連結情況 */ void CreateBiTree_ByString(BiTreeNode**T,char str[]) { BiTreeNode* Stack[MAX]; //棧用於儲存父節點 int top=0,flag=0; BiTreeNode *p=NULL; while(*str) { switch(*str) { case '(': Stack[top++]=p; flag=1; //即將建立左節點 break; case ',': flag=2; //即將建立右節點 break; case ')': --top; //父節點出棧 break; default: { p=(BiTreeNode*)malloc(sizeof(BiTreeNode)); if(NULL==p) return; if(*T==NULL) *T=p; p->data=*str; p->lchild=p->rchild=NULL; switch(flag) { case 1: Stack[top-1]->lchild=p; break; case 2: Stack[top-1]->rchild=p; break; } break; } } //switch(*str) end ++str; } } //遞迴先序遍歷 PreOrderTraverse_Recur(BiTreeNode *T) { if(T) { printf("%2c",T->data); PreOrderTraverse_Recur(T->lchild); PreOrderTraverse_Recur(T->rchild); } } //非遞迴先序遍歷 /* 思路:先訪問父節點,列印。壓棧,訪問左孩子節點,壓棧,直到左孩子為空 然後在訪問右孩子節點 */ void PreOrderTraverse_NoRecur(BiTreeNode*T) { BiTreeNode*Stack[MAX]; int top=0; BiTreeNode *p=T; while(p||top>0) { while(p) { printf("%2c",p->data); Stack[++top]=p; //父節點壓棧 p=p->lchild; } if(top>0) { p=Stack[top--]; p=p->rchild; } } } //遞迴中序遍歷 void InOrderTraverse_Recur(BiTreeNode*T) { if(T) { InOrderTraverse_Recur(T->lchild); printf("%2c",T->data); InOrderTraverse_Recur(T->rchild); } } //非遞迴中序遍歷 /* 思路:一直壓入左孩子,出棧列印節點,壓入右孩子 */ void InOrderTraverse_NoRecur(BiTreeNode*T) { BiTreeNode* Stack[MAX]; int top=0; BiTreeNode*p=T; while(p||top>0) { while(p) { Stack[++top]=p; p=p->lchild; } if(top>0) { p=Stack[top--]; printf("%2c",p->data); p=p->rchild; } } } //遞迴後序遍歷 void AfterOrderTraverse_Recur(BiTreeNode*T) { if(T) { AfterOrderTraverse_Recur(T->lchild); AfterOrderTraverse_Recur(T->rchild); printf("%2c",T->data); } } //非遞迴後序遍歷 /* 1.思路:父節點壓棧,直到左節點為NULL,此時不出棧父節點,直接訪問右孩子,同時 設定q用於檢測是否已經訪問過右孩子 */ void AfterOrderTraverse_NoRecur(BiTreeNode*T) { BiTreeNode*Stack[MAX]; int top=0; BiTreeNode *p=T,*q=NULL; //q用於判斷是否訪問過 while(p||top>0) { while(p) //直到沒有左孩子節點 { Stack[++top]=p; p=p->lchild; } if(top>0) { p=Stack[top]; //不出棧直接訪問右子樹 if(p->rchild==NULL || p->rchild==q) //沒有右子樹或者右節點已經訪問過 { printf("%2c",p->data); q=p; p=NULL; //p置為空,防止再次入棧 top--; } else //有右節點,且沒被訪問過 p=p->rchild; } } } //非遞迴後序遍歷 /* 2.思路:利用棧先入後出的特點,依次將父節點,右孩子,左孩子壓棧 */ void AfterOrderTraverse_NoRecur_2(BiTreeNode*T) { BiTreeNode*Stack[MAX]; int top=0; BiTreeNode *pre,*cur; //cur為當前節點, pre為前節點 pre=NULL; Stack[++top]=T; //根節點入棧 while(top>0) { cur=Stack[top]; //當前節點為葉子結點或者其孩子已經訪問,輸出 if((cur->rchild==NULL&&cur->lchild==NULL)||(pre!=NULL&&(pre==cur->lchild||pre==cur->rchild))) { printf("%2c",cur->data); pre=cur; top--; } else { if(cur->rchild) Stack[++top]=cur->rchild; if(cur->lchild) Stack[++top]=cur->lchild; } } } //銷燬二叉樹 void DestoryBiTree(BiTreeNode*T) { if(T) { if(T->lchild) DestoryBiTree(T->lchild); if(T->rchild) DestoryBiTree(T->rchild); free(T); } } //根據中序和後序遍歷建立二叉樹 inOreder[]儲存中序遍歷,afterOrder[]儲存後序遍歷 BiTreeNode* setBiTree(char inOreder[],char afterOrder[],int m,int n) { if(m>n) return NULL; BiTreeNode *p=(BiTreeNode*)malloc(sizeof(BiTreeNode)); p->data=afterOrder[n]; //後序遍歷最後節點為父節點 p->lchild=p->rchild=NULL; int i,j; for(i=m;inOreder[i]!=afterOrder[n];i++) ; //找到父節點在中序遍歷中的位置 for(j=n-1;j>=i;j--) //使中序陣列和後序陣列相對應 afterOrder[j+1]=afterOrder[j]; p->lchild=setBiTree(inOreder,afterOrder,m,i-1); p->rchild=setBiTree(inOreder,afterOrder,i+1,n); return p; } //中序+先序建立 BiTreeNode* midpreCreate(char mid[],char pre[],int lm,int rm,int lp,int rp) { BiTreeNode *p=(BiTreeNode*)malloc(sizeof(BiTreeNode)); p->data=pre[lp]; p->lchild=p->rchild=NULL; int pos=lm; while(mid[pos]!=pre[lp]) pos++; int childlen=pos-lm; //子樹在字串中的範圍 if(pos>lm) //建立左子樹 p->lchild=midpreCreate(mid,pre,lm,pos-1,lp+1,lp+childlen); if(pos<rm) p->rchild=midpreCreate(mid,pre,pos+1,rm,lp+childlen+1,rp); return p; } //中序+後序建立 BiTreeNode* midpostCreate(char mid[],char post[],int lm,int rm,int lp,int rp) { BiTreeNode *p=(BiTreeNode*)malloc(sizeof(BiTreeNode)); p->data=post[rp]; p->lchild=p->rchild=NULL; int pos=lm; while(mid[pos]!=post[rp]) pos++; int childlen=pos-lm; //子樹在字串中的範圍 if(pos>lm) //建立左子樹 p->lchild=midpostCreate(mid,post,lm,pos-1,lp,lp+childlen-1); if(pos<rm) p->rchild=midpostCreate(mid,post,pos+1,rm,lp+childlen,rp-1); return p; } int main() { //ABD#G##EH##I##CF#J### // BiTreeNode *T=NULL; // CreateBiTree_PreOrder(&T); // puts("遞迴先序遍歷:"); // PreOrderTraverse_Recur(T); puts("\n--按照帶括號的字串輸入------------"); BiTreeNode *T2=NULL; char str[]="a(b(c,d),e(f(,g),h(i)))"; CreateBiTree_ByString(&T2,str); puts("遞迴先序遍歷:"); PreOrderTraverse_Recur(T2); puts(""); // puts("非遞迴先序遍歷:"); // PreOrderTraverse_NoRecur(T2); // puts(""); // puts("遞迴中序遍歷:"); // InOrderTraverse_Recur(T2); // puts(""); // puts("非遞迴中序遍歷:"); // InOrderTraverse_NoRecur(T2); // puts(""); // // puts("遞迴後序遍歷:"); // AfterOrderTraverse_Recur(T2); // puts(""); // puts("非遞迴後序遍歷1:"); // AfterOrderTraverse_NoRecur(T2); // puts(""); // puts("非遞迴後序遍歷2:"); // AfterOrderTraverse_NoRecur_2(T2); // // DestoryBiTree(T2); //銷燬二叉樹 char inOrder[]={'c','b','d','a','f','g','e','i','h'}; char afterOrder[]={'c','d','b','g','f','i','h','e','a'}; char pre[]={'a','b','c','d','e','f','g','h','i'}; // BiTreeNode *T3=setBiTree(inOrder,afterOrder,0,sizeof(inOrder)-1); //呼叫後改變後序陣列 // PreOrderTraverse_Recur(T3); BiTreeNode *T4=midpostCreate(inOrder,afterOrder,0,sizeof(inOrder)-1,0,sizeof(inOrder)-1); puts("\n中+後:"); PreOrderTraverse_Recur(T4); BiTreeNode *T5=midpreCreate(inOrder,pre,0,sizeof(inOrder)-1,0,sizeof(inOrder)-1); puts("\n中+先:"); PreOrderTraverse_Recur(T5); }