1 #include<stdlib.h> 2 #include<stdio.h> 3 4 #define True 1 5 #define False 0 6 7 typedef char TElemType; 8 typedef struct TNode { 9 TElemType data; 10 struct TNode *lchild, *rchild; 11 }TNode,*BinTree; 12 13 int CreateBinTree(BinTree T) 14 { 15 TElemType ch; 16 scanf("%c",&ch); 17 if (ch == '#') 18 T = NULL; 19 else 20 { 21 T = (TNode *)malloc(sizeof(TNode)); 22 T->data = ch; 23 CreateBinTree(T->lchild);//創建左子樹 24 CreateBinTree(T->rchild);//創建右子樹 25 } 26 return 0; 27 } 28 29 void PreOrderTraverse(BinTree T) //先序遍歷 30 { 31 if (T!=NULL) 32 { 33 // Visit(T->data); 34 printf("%c", T->data); 35 PreOrderTraverse(T->lchild); 36 PreOrderTraverse(T->rchild); 37 } 38 } 39 40 void InOrderTraverse(BinTree T) //中序遍歷 41 { 42 if (T != NULL) 43 { 44 InOrderTraverse(T->lchild); 45 // Visit(T->data); 46 printf("%c", T->data); 47 InOrderTraverse(T->rchild); 48 } 49 } 50 51 void PostOrderTraverse(BinTree T) //后序遍歷 52 { 53 if (T != NULL) 54 { 55 PostOrderTraverse(T->lchild); 56 PostOrderTraverse(T->rchild); 57 printf("%c", T->data); 58 } 59 } 60 61 62 63 int main() 64 { 65 BinTree a; 66 CreateBinTree(a); 67 PreOrderTraverse(a); 68 return 0; 69 }
滿懷憧憬寫完了代碼,讓我絕望的是,一運行就出現了問題:能夠輸入樹的信息,但是無法輸出,因此,我認為是二叉樹的遍歷函數出了問題,但是又無法單單從代碼看出
於是,我就寫了如下代碼,自行構建了一個二叉樹:
1 BinTree a=NULL; 2 BinTree b = NULL; 3 BinTree c = NULL; 4 a = (BinTree)malloc(sizeof(TNode)); 5 b = (BinTree)malloc(sizeof(TNode)); 6 c = (BinTree)malloc(sizeof(TNode)); 7 a->rchild = b; 8 b->lchild = c; 9 a->lchild = NULL; 10 b->rchild = NULL; 11 c->lchild = NULL; 12 c->rchild = NULL; 13 a->data = 'A'; 14 b->data = 'B'; 15 c->data = 'C'; 16 17 PreOrderTraverse(a); 18 printf("\n"); 19 InOrderTraverse(a); 20 printf("\n"); 21 PostOrderTraverse(a);
結果卻成功地輸出了自行構造的二叉樹。由此可見我的遍歷函數並沒有問題,因此必定是二叉樹的create函數出了問題,但是為何我卻能夠輸入呢?
我在網上查了查相關的代碼,發現一個采用引用值傳遞的算法,將create函數修改如下:
int CreateBinTree(BinTree &T) //引用值傳遞 { TElemType ch; scanf_s("%c",&ch,sizeof(ch)); if (ch == '#') T = NULL; else { T = (TNode *)malloc(sizeof(TNode)); T->data = ch; CreateBinTree(T->lchild);//構造左子樹 CreateBinTree(T->rchild);//構造右子樹 } return 0; }
嘗試着運行,成功了!
???這時我感到很奇怪。
為啥之前的不行呢?
這時,又看到使用BinTree作返回值的算法,修改后如下:
1 BinTree creatBTree() //以BinTree為返回值 2 { 3 TElemType ch; 4 BinTree T; 5 scanf_s("%c", &ch, sizeof(ch)); 6 if (ch == '#') 7 T = NULL; 8 else 9 { 10 T = (TNode *)malloc(sizeof(TNode)); 11 T->data = ch; 12 T->lchild=creatBTree();//構造左子樹 13 T->rchild=creatBTree();//構造右子樹 14 } 15 return T; 16 }
毫無疑問,同樣能成功實現需求。
那么問題來了?為什么之前的不行呢?
因為我之前用的int CreateBinTree(BinTree T);是單純的值傳遞,就像swap(a,b)無法交換兩值那樣,雖然的確通過動態內存分配和鏈表構造了一個二叉樹,但是在主函數中定義的a的值並沒有任何改變,因此在遍歷a時會毫無反應。
而引用作函數參數傳遞,能夠直接對a的值進行改變,以a為根節點構建二叉樹。
以BinTree為返回值就更不用說了,直接將新構建的二叉樹賦值給a。
為了嘗試地址為參數傳遞是否可行,寫了如下函數
int CreateRoot(BinTree *T),細節如下:
1 int CreateBinTree(BinTree *T) 2 { 3 TElemType ch; 4 scanf("%c",&ch); 5 *T=(BinTree)malloc(sizeof(TNode)); 6 (*T)->data=ch; 7 (*T)->lchild=NULL; 8 (*T)->rchild=NULL;//設置左右孩子為NULL,以防陷入無限循環 9 }
能夠成功插入根節點!
看到這里,便可以輕松完成遞歸構造函數:
1 int CreateBinTree(BinTree *T) 2 { 3 TElemType ch; 4 scanf("%c",&ch); 5 if (ch == '#') 6 *T = NULL; //若寫成T=NULL ,可能會陷入無限循環 7 else 8 { 9 *T = (BinTree)malloc(sizeof(TNode)); 10 (*T)->data = ch; 11 CreateBinTree(&(*T)->lchild);//left child 12 CreateBinTree(&(*T)->rchild);//right child 13 } 14 return 0; 15 } 16 //在本函數中最需要注意的就是,所有地方都必須以(*T)的形式出現
寫完這個隨筆,對二叉樹的理解增進了不少,今天的學習給我帶來了不小的回報,繼續努力~