二叉樹遍歷方式和實現,以及二叉樹查找、統計個數、比較、求深度

二叉樹遍歷方式和實現,以及二叉樹查找、統計個數、比較、求深度


一、基本概念

每個結點最多有兩棵子樹,左子樹和右子樹,次序不可以顛倒。

性質:

1、非空二叉樹的第n層上至多有2^(n-1)個元素。

2、深度爲h的二叉樹至多有2^h-1個結點。

滿二叉樹:所有終端都在同一層次,且非終端結點的度數爲2。

在滿二叉樹中若其深度爲h,則其所包含的結點數必爲2^h-1。

完全二叉樹:除了最大的層次即成爲一顆滿二叉樹且層次最大那層所有的結點均向左靠齊,即集中在左面的位置上,不能有空位置。

對於完全二叉樹,設一個結點爲i則其父節點爲i/2,2i爲左子節點,2i+1爲右子節點。

二、存儲結構

順序存儲:

將數據結構存在一塊固定的數組中。

  1. #define LENGTH 100  
  2. typedef char datatype;  
  3. typedef struct node{  
  4.     datatype data;  
  5.     int lchild,rchild;  
  6.     int parent;  
  7. }Node;  
  8.   
  9. Node tree[LENGTH];  
  10. int length;  
  11. int root;  

   雖然在遍歷速度上有一定的優勢,但因所佔空間比較大,是非主流二叉樹。二叉樹通常以鏈式存儲。

鏈式存儲:

  1. typedef char datatype;  
  2.   
  3. typedef struct BinNode{  
  4.     datatype data;  
  5.     struct BinNode* lchild;  
  6.     struct BinNode* rchild;  
  7. }BinNode;  
  8.   
  9. typedef BinNode* bintree;          //bintree本身是個指向結點的指針  


 三、二叉樹的遍歷

遍歷即將樹的所有結點訪問且僅訪問一次。按照根節點位置的不同分爲前序遍歷(先序遍歷),中序遍歷,後序遍歷。另外還有一個遍歷方式—層次遍歷

前序遍歷:根節點->左子樹->右子樹

中序遍歷:左子樹->根節點->右子樹

後序遍歷:左子樹->右子樹->根節點

例如:求下面樹的四種遍歷

 

前序遍歷:abdefgc

中序遍歷:debgfac

後序遍歷:edgfbca

層次遍歷:abcdfeg

四、遍歷的實現

遞歸實現(以前序遍歷爲例,其他的只是輸出的位置稍有不同)

  1. void preorder(bintree t){  
  2.     if(t){  
  3.         printf("%c ",t->data);  
  4.         preorder(t->lchild);  
  5.         preorder(t->rchild);  
  6.     }  
  7. }  


非遞歸的實現

因爲當遍歷過根節點之後還要回來,所以必須將其存起來。考慮到後進先出的特點,選用棧存儲。數量確定,以順序棧存儲。

  1. #define SIZE 100  
  2. typedef struct seqstack{  
  3.     bintree data[SIZE];  
  4.     int tag[SIZE];   //爲後續遍歷準備的  
  5.     int top;     //top爲數組的下標  
  6. }seqstack;  
  7.   
  8. void push(seqstack *s,bintree t){  
  9.   
  10.     if(s->top == SIZE){  
  11.         printf("the stack is full\n");  
  12.     }else{  
  13.         s->top++;  
  14.         s->data[s->top]=t;  
  15.     }  
  16. }  
  17.   
  18. bintree pop(seqstack *s){  
  19.     if(s->top == -1){  
  20.         return NULL;  
  21.     }else{  
  22.         s->top--;  
  23.         return s->data[s->top+1];  
  24.     }  
  25. }  

1、前序遍歷 

  1. void preorder_dev(bintree t){  
  2.     seqstack s;  
  3.     s.top = -1;     //因爲top在這裏表示了數組中的位置,所以空爲-1  
  4.     if(!t){  
  5.         printf("the tree is empty\n");  
  6.     }else{  
  7.         while(t || s.stop != -1){  
  8.             while(t){    //只要結點不爲空就應該入棧保存,與其左右結點無關      
  9.                   printf("%c ",t->data);  
  10.                 push(&s,t);  
  11.                 t= t->lchild;  
  12.             }  
  13.             t=pop(&s);  
  14.             t=t->rchild;  
  15.         }  
  16.     }  
  17. }  


 2、中序遍歷

 

  1. void midorder(bintree t){  
  2.     seqstack s;  
  3.     s.top = -1;  
  4.     if(!t){  
  5.         printf("the tree is empty!\n");  
  6.     }else{  
  7.         while(t ||s.top != -1){  
  8.             while(t){  
  9.                 push(&s,t);  
  10.                 t= t->lchild;  
  11.             }  
  12.             t=pop(&s);  
  13.             printf("%c ",t->data);  
  14.             t=t->rchild;  
  15.         }  
  16.     }  
  17. }  

 

3、後序遍歷

因爲後序遍歷最後還要要訪問根結點一次,所以要訪問根結點兩次。採取夾標誌位的方法解決這個問題。

這段代碼非常糾結,對自己有信心的朋友可以嘗試獨立寫一下。反正我是寫了很長時間。邏輯不難,我畫了一張邏輯圖:

 代碼:

 

  1. void postorder_dev(bintree t){  
  2.     seqstack s;  
  3.     s.top = -1;  
  4.     if(!t){  
  5.         printf("the tree is empty!\n");  
  6.     }else{  
  7.         while(t || s.top != -1){    //棧空了的同時t也爲空。  
  8.             while(t){  
  9.                 push(&s,t);  
  10.                 s.tag[s.top] = 0;   //設置訪問標記,0爲第一次訪問,1爲第二次訪問  
  11.                 t= t->lchild;  
  12.             }  
  13.             if(s.tag[s.top] == 0){  //第一次訪問時,轉向同層右結點  
  14.                 t= s.data[s.top];   //左走到底時t是爲空的,必須有這步!  
  15.                 s.tag[s.top]=1;       
  16.                 t=t->rchild;  
  17.             }else {  
  18.                 while (s.tag[s.top] == 1){ //找到棧中下一個第一次訪問的結點,退出循環時並沒有pop所以爲其左子結點  
  19.                     t = pop(&s);  
  20.                     printf("%c ",t->data);  
  21.                 }  
  22.                 t = NULL; //必須將t置空。跳過向左走,直接向右走  
  23.             }  
  24.         }  
  25.     }  
  26. }  


 4、層次遍歷:即每一層從左向右輸出

元素需要儲存有先進先出的特性,所以選用隊列存儲。

隊列的定義:

  1. #define MAX 1000  
  2.   
  3. typedef struct seqqueue{  
  4.     bintree data[MAX];  
  5.     int front;  
  6.     int rear;  
  7. }seqqueue;  
  8.   
  9.   
  10. void enter(seqqueue *q,bintree t){  
  11.     if(q->rear == MAX){  
  12.         printf("the queue is full!\n");  
  13.     }else{  
  14.         q->data[q->rear] = t;  
  15.         q->rear++;  
  16.     }  
  17. }  
  18.   
  19. bintree del(seqqueue *q){  
  20.     if(q->front == q->rear){  
  21.         return NULL;  
  22.     }else{  
  23.         q->front++;  
  24.         return q->data[q->front-1];  
  25.     }  
  26. }  


遍歷實現 

  1. void level_tree(bintree t){  
  2.     seqqueue q;  
  3.     bintree temp;  
  4.     q.front = q.rear = 0;  
  5.     if(!t){  
  6.         printf("the tree is empty\n");  
  7.         return ;  
  8.     }  
  9.     enter(&q,t);  
  10.     while(q.front != q.rear){  
  11.         t=del(&q);  
  12.         printf("%c ",t->data);  
  13.         if(t->lchild){  
  14.             enter(&q,t->lchild);  
  15.         }  
  16.         if(t->rchild){  
  17.             enter(&q,t->rchild);  
  18.         }  
  19.     }  
  20. }  


 

5、利用前序遍歷的結果生成二叉樹

  1. //遞歸調用,不存點,想的時候只關注於一個點,因爲還會回來的,不要跟蹤程序運行,否則容易多加循環  
  2.   
  3. void createtree(bintree *t){        
  4.     datatype c;  
  5.     if((c=getchar()) == '#')  
  6.         *t = NULL;  
  7.     else{  
  8.         *t = (bintree)malloc(sizeof(BinNode));  
  9.         (*t)->data = c;  
  10.         createtree(&(*t)->lchild);  
  11.         createtree(&(*t)->rchild);  
  12.     }  
  13. }  


6、二叉樹的查找

  1. bintree search_tree(bintree t,datatype x){  
  2.     if(!t){  
  3.         return NULL;  
  4.     }  
  5.     if(t->data == x){  
  6.         return t;  
  7.     }else{  
  8.         if(!search_tree(t->lchild,x)){  
  9.             return search_tree(t->rchild,x);  
  10.         }  
  11.         return t;  
  12.     }  
  13. }  


7、統計結點個數

  1. int count_tree(bintree t){  
  2.     if(t){  
  3.         return (count_tree(t->lchild)+count_tree(t->rchild)+1);  
  4.     }  
  5.     return 0;  
  6. }  


8、比較兩個樹是否相同

  1. int is_equal(bintree t1,bintree t2){  
  2.     if(!t1 && !t2){      //都爲空就相等  
  3.         return 1;  
  4.     }  
  5.     if(t1 && t2 && t1->data == t2->data){      //有一個爲空或數據不同就不判斷了  
  6.         if(is_equal(t1->lchild,t2->lchild))  
  7.             if(is_equal(t1->rchild,t2->rchild)){  
  8.                 return 1;  
  9.             }  
  10.     }  
  11.     return 0;  
  12. }  


9、求二叉樹的深度

  1. int hight_tree(bintree t){  
  2.     int h,left,right;  
  3.     if(!t){  
  4.         return 0;  
  5.     }  
  6.     left = hight_tree(t->lchild);  
  7.     right = hight_tree(t->rchild);  
  8.     h = (left>right?left:right)+1;  
  9.     return h;  
  10. }  

轉載地址:點擊打開鏈接



發佈了34 篇原創文章 · 獲贊 65 · 訪問量 28萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章