數據結構--樹--線索二叉樹(中序,前序,後序)

線索二叉樹
在遍歷二叉樹的時候,會有許多空指針域,這些空間不存儲任何事物,白白浪費了內存的資源。
那麼在做遍歷的時候,提前記錄下每個結點的前驅和後繼,這樣就更加節約了時間。
                 [ lchild ] [ LTag ] [ data ] [ RTag ] [ rchild ]
LTag  = { 0 : lchild 域指示結點的左孩子 1 : lchild 域指示結點的前驅 }
RTag = { 0 : rchild 域指示結點的右孩子 1 : rchild 域指示結點的後繼 }  
以這種結點結構構成的二叉鏈表作爲二叉樹的存儲結構,叫做線索鏈表,其中,指向結點前驅和後繼的指針,叫做線索。
加上線索的二叉樹叫做線索二叉樹(Threaded Binary Tree)
對二叉樹以某種次序遍歷使其變成線索二叉樹的過程叫做線索化


★線索二叉樹結構:

    #define TElemType char
    typedef enum{
        Link,Thread
    }PointerTag;//Link == 0 :指針 ,Thread == 1: 線索
    typedef struct BiThrNode{
        TElemType data;
        struct BiThrNode *lchild, *rchild; //左右孩子指針
        PointerTag LTag , RTag;            //左右標誌
    }BiThrNode, *BiThrTree;


                 [ lchild ] [ LTag ] [ data ] [ RTag ] [ rchild ]
LTag  = { 0 : lchild 域指示結點的左孩子 1 : lchild 域指示結點的前驅 }
RTag = { 0 : rchild 域指示結點的右孩子 1 : rchild 域指示結點的後繼 }  


★線索化二叉樹之前,咱們先把樹建起來(用前序遍歷建樹)

    //char Vexch[20]={'H','D','A','$','$','C','$','B','$','$','G','F','$','E','$','$','$'};  
    char Vexch[26]={'A','B','D','H','$','$','I','$','$','E','J','$','$','$','C','F','$','$','G','$','$'};  
    int i=0;  
    //二叉樹的創建  
    Status CreatBiThrTree(BiThrTree &T)  
    {  
        if(Vexch[i++]=='$') T=NULL;  
        else  
        {  
            T= (BiThrTree)malloc(sizeof(BiThrNode));
            if(!T)  return 0;  
            T->data=Vexch[i-1];//生成根節點  
            printf("%5c",T->data);
            T->LTag=Link;  
            CreatBiThrTree(T->lchild);//創建左子樹
            T->RTag=Link;
            CreatBiThrTree(T->rchild);//創建右子樹  
        }  
        return 1;  
    }  


建立樹爲該樹:
 

遍歷visit()函數

    Status visit(TElemType e){
        printf("%5c",e);
        return OK;
    }


(1)中序遍歷,線索二叉樹
【讓一棵樹 直接變成一個線性表去遍歷】
遍歷 順序爲:H - >D - > I - > B  - > J - > E - > A - > F - > C - >  G
【建立二叉樹頭結點】(下面的代碼沒有循環,只是單純的建立了一個頭結點,連接上主體的樹部分,方便遍歷。)

    //建立頭結點,中序線索二叉樹
    Status InOrderThreading(BiThrTree &Thrt,BiThrTree T){
        //中序遍歷二叉樹T,並將其中序線索化,Thrt指向頭結點。
        if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
            return ERROR;
        
        Thrt->RTag = Link;  //建頭結點
        Thrt->rchild = Thrt ;                    //右指針回指
        if(!T){
            Thrt->lchild = Thrt;
            Thrt->LTag = Link;
        }else{
            pre = Thrt ;
            Thrt->lchild = T;
            Thrt->LTag = Link;
            InThreading(T);
            pre->rchild = Thrt ;
            pre->RTag = Thread;
            Thrt->rchild = pre;
        }
        return OK;
    }

【解釋】(pre永遠指向上一個節點)
Thrt 就是 下圖的空指針, 初始化 pre 爲 這個空指針,完成下圖的【1】【2】步驟
做完樹的線索化後,pre 已經到了最後一個節點,那麼就可以完成【3】【4】兩個步驟了
如下圖所示。
【1】讓最左的結點,就是中序遍歷時 第一個結點的左指針指向 空的頭結點。
【第一個結點的左標記肯定是 Thread而不是 link ,這樣就能找到最左的結點】 那麼既然是線索Thread,就讓他指向空的頭結點(反正空着也是空着)
【2】頭結點順下來,從左子樹開始找
【3】因爲空節點的右標記是 Thread線索,那麼讓他指向最右的,最終結點。(反正空着也是空着)
【4】最終結點G的右線索指向頭結點,標記着終結。
構成循環:
                    ↓   →  →  →  →   【  空的頭結點】 ← ←  ←  ← ↑
                   H → D →  I → B  →  J → E →  A → F →  C →  G
 

★LTag  = { 0 : lchild 域指示結點的左孩子 1 : lchild 域指示結點的前驅 } RTag = { 0 : rchild 域指示結點的右孩子 1 : rchild 域指示結點的後繼 }  
概括爲:LTag=0(Link)【左孩子】,LTag=1(Thread)【前驅】;RTag=0(Link)【右孩子】 ,RTag=1(Thread)【後繼】
【問】那麼怎樣的稱爲Link指針 ,怎樣的 稱爲 Thread 線索

【答】可以這樣理解,Link指針是本來建樹的時候就有的,而Thread線索是爲了線索化,而增添的。


【中序遍歷線索化】

    BiThrTree pre;  //全局變量,始終指向剛剛訪問過的結點。
    void InThreading(BiThrTree p){
        if(p){
            InThreading(p->lchild);     //左子樹線索化
            if(!p->lchild){             //沒有左孩子
                p->LTag = Thread;       //前驅線索
                p->lchild = pre;        //左孩子指針指向前驅
            }
            if(!pre->rchild){
                pre->RTag = Thread;       //後繼線索
                pre->rchild = p ;         //前驅右孩子指針指向後繼
            }
            pre = p;
            InThreading(p->rchild);   //右子樹線索化
        }
    }

【解釋】
首先,很明顯:中序遍歷線索化,其實也是基於中序遍歷的。(從代碼中可以看出)
也是先左,再中,後右(左 > 中 > 右)
只是在中間部分,對結點的處理的時候,有些不一樣。1、中序遍歷時是輸出。2、而現在我們把它替換爲 處理標記和指針。
介紹如何處理,很簡單:
★沒有左孩子,或者沒有右孩子那肯定是線索,而不是指針
★因爲是中序,遍歷肯定是從左到右,那麼左邊的線索肯定是指向前驅的,右邊的線索肯定是指向後繼的。


【中序遍歷】

    //中序 遍歷線索二叉樹
    Status InOrderTraverse_Thr(BiThrTree T ,Status(* visit)(TElemType e) ){
        //T指向頭結點,頭結點的左鏈lchild指向根節點,可參見線索化算法
        //中序遍歷二叉線索樹T的非遞歸算法,對每個數據元素調用函數visit
        BiThrTree p ;
        p = T->lchild;            // p指向根節點
        while(p != T){                      //空樹 或者遍歷結束時 p == T
            while(p->LTag == Link )         // 走到最左結點
                p = p->lchild;
            visit(p->data);  
            while(p->RTag == Thread && p->rchild !=T){
                p = p->rchild ;             // 若有右線索,
                visit(p->data);
            }
            p = p->rchild;
        }
        return OK;
    }

【解釋】
最外面的while 從上面構造的時候就已經說明了,當p回到T的時候,那麼就標記結束了。
裏面的第一個 while(p->LTag == Link) 循環,走到最左結點
輸出該節點
while(p->RTag == Thread && p->rchild !=T)  如果右邊有線索,且指向的不是最後的根T, 優先按着線索走。
發現這裏沒有線索了,那麼就繼續往右孩子找。


【總的中序遍歷線索二叉樹代碼】

    #include <iostream>
    #include <string.h>
    #include <cstdio>
    #include <stdlib.h>
    using namespace std;
    #define Status int
    #define OK 1
    #define ERROR 0
    #define TElemType char
    typedef enum{
        Link,Thread
    }PointerTag;//Link == 0 :指針 ,Thread == 1: 線索
    typedef struct BiThrNode{
        TElemType data;
        struct BiThrNode *lchild, *rchild; //左右孩子指針
        PointerTag LTag , RTag;            //左右標誌
    }BiThrNode, *BiThrTree;
     
    //char Vexch[20]={'H','D','A','$','$','C','$','B','$','$','G','F','$','E','$','$','$'};  
    char Vexch[26]={'A','B','D','H','$','$','I','$','$','E','J','$','$','$','C','F','$','$','G','$','$'};  
    int i=0;  
    //二叉樹的創建  
    Status CreatBiThrTree(BiThrTree &T)  
    {  
        if(Vexch[i++]=='$') T=NULL;  
        else  
        {  
            T= (BiThrTree)malloc(sizeof(BiThrNode));
            if(!T)  return 0;  
            T->data=Vexch[i-1];//生成根節點  
            printf("%5c",T->data);
            T->LTag=Link;  
            CreatBiThrTree(T->lchild);//創建左子樹
            T->RTag=Link;
            CreatBiThrTree(T->rchild);//創建右子樹  
        }  
        return 1;  
    }  
    Status visit(TElemType e){
        printf("%5c",e);
        return OK;
    }
     
    BiThrTree pre;  //全局變量,始終指向剛剛訪問過的結點。
    void InThreading(BiThrTree p){
        if(p){
            InThreading(p->lchild);     //左子樹線索化
            if(!p->lchild){             //沒有左孩子
                p->LTag = Thread;       //前驅線索
                p->lchild = pre;        //左孩子指針指向前驅
            }
            if(!pre->rchild){
                pre->RTag = Thread;       //後繼線索
                pre->rchild = p ;         //前驅右孩子指針指向後繼
            }
            pre = p;
            InThreading(p->rchild);   //右子樹線索化
        }
    }
    //建立頭結點,中序線索二叉樹
    Status InOrderThreading(BiThrTree &Thrt,BiThrTree T){
        //中序遍歷二叉樹T,並將其中序線索化,Thrt指向頭結點。
        if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
            return ERROR;
        
        Thrt->RTag = Link;  //建頭結點
        Thrt->rchild = Thrt ;                    //右指針回指
        if(!T){
            Thrt->lchild = Thrt;
            Thrt->LTag = Link;
        }else{
            pre = Thrt ;
            Thrt->lchild = T;
            Thrt->LTag = Link;
            InThreading(T);
            pre->rchild = Thrt ;
            pre->RTag = Thread;
            Thrt->rchild = pre;
        }
        return OK;
    }
    //中序 遍歷線索二叉樹
    Status InOrderTraverse_Thr(BiThrTree T ,Status(* visit)(TElemType e) ){
        //T指向頭結點,頭結點的左鏈lchild指向根節點,可參見線索化算法
        //中序遍歷二叉線索樹T的非遞歸算法,對每個數據元素調用函數visit
        BiThrTree p ;
        p = T->lchild;            // p指向根節點
        while(p != T){                      //空樹 或者遍歷結束時 p == T
            while(p->LTag == Link )         // 走到最左結點
                p = p->lchild;
            visit(p->data);  
            while(p->RTag == Thread && p->rchild !=T){
                p = p->rchild ;             // 若有右線索,
                visit(p->data);
            }
            p = p->rchild;
        }
        return OK;
    }
    int main()
    {
        BiThrTree T, inorderT;
        printf("創建樹\n");
        CreatBiThrTree(T);
        printf("\n中序遍歷線索二叉樹\n");
        InOrderThreading(inorderT , T);
        InOrderTraverse_Thr(inorderT , visit);
        printf("\n");
        return 0;
    }

 


(2)前序遍歷,線索二叉樹


【前序遍歷二叉樹線索化】

    BiThrTree pre;  //全局變量,始終指向剛剛訪問過的結點。
    void PreThreading(BiThrTree p){
        if(p){
            if(!p->lchild){             //沒有左孩子
                p->LTag = Thread;       //前驅線索
                p->lchild = pre;        //左孩子指針指向前驅
            }
            if(!pre->rchild && pre){
                pre->RTag = Thread;       //後繼線索
                pre->rchild = p ;         //前驅右孩子指針指向後繼
            }
            pre = p;
            if(p->LTag == Link)
                PreThreading(p->lchild);     //左子樹線索化
            if(p->RTag == Link)
                PreThreading(p->rchild);   //右子樹線索化
        }
    }

【建立頭結點】(和中序遍歷一樣)

    //建立頭結點,前序線索二叉樹
    Status PreOrderThreading(BiThrTree &Thrt,BiThrTree T){
        //前序遍歷二叉樹T,並將其前序線索化,Thrt指向頭結點。
        if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
            return ERROR;
        
        Thrt->RTag = Thread;               //建頭結點
        Thrt->rchild = Thrt ;              //右指針回指
        Thrt->LTag = Link;
        if(!T){
            Thrt->lchild = Thrt;
        }else{
            Thrt->lchild = T;
            pre = Thrt ;
            PreThreading(T);
            pre->rchild = Thrt ;
            pre->RTag = Thread;
            Thrt->rchild = pre;
        }
        return OK;
    }


                                                                               ↓  ← 【  空的頭結點  】 ← ←  ←  ←  ←  ←  ←   ↑
                                                                               A → B →  D → H  →  I →  E →  J → C →  F →  G


   

         1、A的直接前驅

          ㈠若LTag 的值爲1,那麼LChild 所指結點就是直接前驅

          ㈡若LTag 的值爲0,那麼

                 ⒈若A爲雙親左兒子,那麼直接前驅就是A的雙親結點

                 ⒉若A爲雙親右兒子,那麼直接前驅就是A的雙親左兒子

         2、A的直接後繼

          ㈠若RTag 的值爲1,那麼RChild 所指結點就是直接後繼

          ㈡若RTag 的值爲0,那麼

                  ⒈若LTag 的值爲0,那麼直接後繼就是其左兒子。

                  ⒉若LTag 的值爲1,那麼直接後繼就是其右兒子。

【前序遍歷二叉樹】

    //前序 遍歷線索二叉樹
    Status PreOrderTraverse_Thr(BiThrTree T ,Status(* visit)(TElemType e) ){
        //T指向頭結點,頭結點的左鏈lchild指向根節點,可參見線索化算法
        //前序遍歷二叉線索樹T的非遞歸算法,對每個數據元素調用函數visit
        BiThrTree p ;
        p = T->lchild;            // p指向根節點
        while(p != T){            //空樹 或者遍歷結束時 p == T
            visit(p->data);  
            if(p->LTag == Link)
                p = p->lchild;
            else
                p = p->rchild;
        }
        return OK;
    }


【總的前序遍歷線索二叉樹代碼】

    #include <iostream>
    #include <string.h>
    #include <cstdio>
    #include <stdlib.h>
    using namespace std;
    #define Status int
    #define OK 1
    #define ERROR 0
    #define TElemType char
     
    typedef enum{
        Link,Thread
    }PointerTag;//Link == 0 :指針 ,Thread == 1: 線索
    typedef struct BiThrNode{
        TElemType data;
        struct BiThrNode *lchild, *rchild; //左右孩子指針
        PointerTag LTag , RTag;            //左右標誌
    }BiThrNode, *BiThrTree;
     
    //char Vexch[20]={'H','D','A','$','$','C','$','B','$','$','G','F','$','E','$','$','$'};  
    char Vexch[26]={'A','B','D','H','$','$','I','$','$','E','J','$','$','$','C','F','$','$','G','$','$'};  
    int i=0;  
    //二叉樹的創建  
    Status CreatBiThrTree(BiThrTree &T)  
    {  
        if(Vexch[i++]=='$') T=NULL;  
        else  
        {  
            T= (BiThrTree)malloc(sizeof(BiThrNode));
            if(!T)  return 0;  
            T->data=Vexch[i-1];//生成根節點  
            printf("%5c",T->data);
            T->LTag=Link;
            CreatBiThrTree(T->lchild);//創建左子樹
            T->RTag=Link;
            CreatBiThrTree(T->rchild);//創建右子樹  
        }  
        return 1;  
    }  
    Status visit(TElemType e){
        printf("%5c",e);
        return OK;
    }
     
    BiThrTree pre;  //全局變量,始終指向剛剛訪問過的結點。
    void PreThreading(BiThrTree p){
        if(p){
            if(!p->lchild){             //沒有左孩子
                p->LTag = Thread;       //前驅線索
                p->lchild = pre;        //左孩子指針指向前驅
            }
            if(!pre->rchild){
                pre->RTag = Thread;       //後繼線索
                pre->rchild = p ;         //前驅右孩子指針指向後繼
            }
            pre = p;
            if(p->LTag == Link)
                PreThreading(p->lchild);     //左子樹線索化
            if(p->RTag == Link)
                PreThreading(p->rchild);   //右子樹線索化
        }
    }
    //建立頭結點,前序線索二叉樹
    Status PreOrderThreading(BiThrTree &Thrt,BiThrTree T){
        //前序遍歷二叉樹T,並將其前序線索化,Thrt指向頭結點。
        if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
            return ERROR;
        
        Thrt->RTag = Thread;               //建頭結點
        Thrt->rchild = Thrt ;              //右指針回指
        Thrt->LTag = Link;
        if(!T){
            Thrt->lchild = Thrt;
        }else{
            Thrt->lchild = T;
            pre = Thrt ;
            PreThreading(T);
            pre->rchild = Thrt ;
            pre->RTag = Thread;
            Thrt->rchild = pre;
        }
        return OK;
    }
    //前序 遍歷線索二叉樹
    Status PreOrderTraverse_Thr(BiThrTree T ,Status(* visit)(TElemType e) ){
        //T指向頭結點,頭結點的左鏈lchild指向根節點,可參見線索化算法
        //前序遍歷二叉線索樹T的非遞歸算法,對每個數據元素調用函數visit
        BiThrTree p ;
        p = T->lchild;            // p指向根節點
        while(p != T){            //空樹 或者遍歷結束時 p == T
            visit(p->data);  
            if(p->LTag == Link)
                p = p->lchild;
            else
                p = p->rchild;
        }
        return OK;
    }
    int main()
    {
        BiThrTree T, PreT;
        printf("創建樹\n");
        CreatBiThrTree(T);
        printf("\n前序遍歷線索二叉樹\n");
        PreOrderThreading(PreT , T);
        PreOrderTraverse_Thr(PreT , visit);
        printf("\n");
        return 0;
    }

 

(3)後序遍歷,線索二叉樹

【後序遍歷線索二叉樹時,需要一個parent 指針,所以建樹的時候與上面兩個有所不同】

    #define TElemType char
    typedef enum{
        Link,Thread
    }PointerTag;//Link == 0 :指針 ,Thread == 1: 線索
    typedef struct BiThrNode{
        TElemType data;
        struct BiThrNode *lchild, *rchild; //左右孩子指針
        struct BiThrNode *parent;
        PointerTag LTag , RTag;            //左右標誌
    }BiThrNode, *BiThrTree;
    BiThrTree pre;  //全局變量,始終指向剛剛訪問過的結點。
     
    Status visit(TElemType e){
        printf("%5c",e);
        return OK;
    }
    //char Vexch[20]={'H','D','A','$','$','C','$','B','$','$','G','F','$','E','$','$','$'};  
    char Vexch[26]={'A','B','D','H','$','$','I','$','$','E','J','$','$','$','C','F','$','$','G','$','$'};  
    int i=0;  
    //二叉樹的創建  
    Status CreatBiThrTree(BiThrTree &T,BiThrTree &p)  
    {  
        if(Vexch[i++]=='$') T=NULL;  
        else  
        {  
            T= (BiThrTree)malloc(sizeof(BiThrNode));
            if(!T)  return 0;  
            T->data=Vexch[i-1];//生成根節點  
        T->parent = p;//指回原來的結點
            visit(T->data);
            T->LTag=Link;
            CreatBiThrTree(T->lchild,T);//創建左子樹
            T->RTag=Link;
            CreatBiThrTree(T->rchild,T);//創建右子樹  
        }  
        return 1;  
    }  

 

【後序遍歷二叉樹線索化】

    void PostThreading(BiThrTree p){
        if(p){
            PostThreading(p->lchild);     //左子樹線索化
            PostThreading(p->rchild);     //右子樹線索化
            if(!p->lchild){               //沒有左孩子
                p->LTag = Thread;         //前驅線索
                p->lchild = pre;          //左孩子指針指向前驅
            }
            if(pre && !pre->rchild){
                pre->RTag = Thread;       //後繼線索
                pre->rchild = p ;         //前驅右孩子指針指向後繼
            }
            pre = p;
        }
    }

【建立頭結點】(這裏就不建頭結點了,因爲入口是總根節點,出口也是總根節點)


   

         1、A的直接前驅

          ㈠若LTag 的值爲1,那麼A的直接前驅爲LChild所指結點

          ㈡若LTag 的值爲0,那麼

                  ⒈若有左兒子,那麼直接前驅就是A的左兒子。

                  ⒉若有右兒子,那麼直接前驅就是A的右兒子。

         2、A的直接後繼

          ㈠若結點A是二叉樹的根,則其後繼爲空

          ㈡若結點A是其雙親的右兒子,或是雙親的左孩子且其雙親沒有左子樹沒有右子樹,則其後繼即爲雙親結點

          ㈢若結點A是其雙親的左兒子,且雙親有右子樹,則其後繼爲雙親的右子樹上按後序遍歷列出來的第一個結點。


【後序遍歷二叉樹】

    //後序 遍歷線索二叉樹
    Status PostOrderTraverse_Thr(BiThrTree T ,Status(* visit)(TElemType e) ){
        BiThrTree p ;
        p = T;            // p指向根節點
        pre=NULL;
        while(p != NULL){            //空樹 或者遍歷結束時 p == T
            while(p->LTag == Link )         // 走到最左結點  ||左結點
                p = p->lchild;
            
            while(p->RTag == Thread ){      //訪問後繼       ||右結點
                visit(p->data);
                pre = p;
                p = p->rchild ;            
            }
            if(p == T){                     //是否是最後根節點
                visit(p->data);
                break;
            }
            while(p && p->rchild == pre  ){ //訪問根         ||根節點
                visit(p->data);
                pre = p;
                p = p->parent;
            }
            if(p && p->RTag == Link)
                p = p->rchild;
        }
        return OK;
    }

 

【總的後序遍歷線索二叉樹代碼】

    #include <iostream>
    #include <string.h>
    #include <cstdio>
    #include <stdlib.h>
    using namespace std;
    #define Status int
    #define OK 1
    #define ERROR 0
    #define TElemType char
    typedef enum{
        Link,Thread
    }PointerTag;//Link == 0 :指針 ,Thread == 1: 線索
    typedef struct BiThrNode{
        TElemType data;
        struct BiThrNode *lchild, *rchild; //左右孩子指針
        struct BiThrNode *parent;
        PointerTag LTag , RTag;            //左右標誌
    }BiThrNode, *BiThrTree;
    BiThrTree pre;  //全局變量,始終指向剛剛訪問過的結點。
     
    Status visit(TElemType e){
        printf("%5c",e);
        return OK;
    }
    //char Vexch[20]={'H','D','A','$','$','C','$','B','$','$','G','F','$','E','$','$','$'};  
    char Vexch[26]={'A','B','D','H','$','$','I','$','$','E','J','$','$','$','C','F','$','$','G','$','$'};  
    int i=0;  
    //二叉樹的創建  
    Status CreatBiThrTree(BiThrTree &T,BiThrTree &p)  
    {  
        if(Vexch[i++]=='$') T=NULL;  
        else  
        {  
            T= (BiThrTree)malloc(sizeof(BiThrNode));
            if(!T)  return 0;  
            T->data=Vexch[i-1];//生成根節點  
            T->parent = p;
            visit(T->data);
            T->LTag=Link;
            CreatBiThrTree(T->lchild,T);//創建左子樹
            T->RTag=Link;
            CreatBiThrTree(T->rchild,T);//創建右子樹  
        }  
        return 1;  
    }  
     
    void PostThreading(BiThrTree p){
        if(p){
            PostThreading(p->lchild);     //左子樹線索化
            PostThreading(p->rchild);     //右子樹線索化
            if(!p->lchild){               //沒有左孩子
                p->LTag = Thread;         //前驅線索
                p->lchild = pre;          //左孩子指針指向前驅
            }
            if(pre && !pre->rchild){
                pre->RTag = Thread;       //後繼線索
                pre->rchild = p ;         //前驅右孩子指針指向後繼
            }
            pre = p;
        }
    }
    //後序 遍歷線索二叉樹
    Status PostOrderTraverse_Thr(BiThrTree T ,Status(* visit)(TElemType e) ){
        BiThrTree p ;
        p = T;            // p指向根節點
        pre=NULL;
        while(p != NULL){            //空樹 或者遍歷結束時 p == T
            while(p->LTag == Link )         // 走到最左結點  ||左結點
                p = p->lchild;
            
            while(p->RTag == Thread ){      //訪問後繼       ||右結點
                visit(p->data);
                pre = p;
                p = p->rchild ;            
            }
            if(p == T){                     //是否是最後根節點
                visit(p->data);
                break;
            }
            while(p && p->rchild == pre  ){ //訪問根         ||根節點
                visit(p->data);
                pre = p;
                p = p->parent;
            }
            if(p && p->RTag == Link)
                p = p->rchild;
        }
        return OK;
    }
    int main()
    {
        BiThrTree PostT;
        printf("創建樹\n");
        pre = NULL;
        CreatBiThrTree(PostT,pre);
        printf("\n後序遍歷線索二叉樹\n");
        PostThreading(PostT);
        PostOrderTraverse_Thr(PostT , visit);
        printf("\n");
        return 0;
    }

 

 

總結:
【問】爲什麼用先序遍歷建樹後,可以用來中序遍歷線索化?
【答】先序遍歷建樹,只是一種建樹方式(當然可以用別的方法來建樹,但是數組裏的順序可能就要變化了),建完樹後,跟後面線索化無關。


【問】爲什麼中序遍歷,先序遍歷,後序遍歷在線索化的時候,要用不同的線索化?
【答】因爲中序,先序,後序,他們的前驅和後繼是不一樣的,根據代碼也知道是不一樣。


【問】對於做題,畫已知二叉樹的前序、中序、後序線索二叉樹有什麼技巧嗎?

【答】可以先將 二叉樹前序、中序、後序遍歷 順序寫出來。再根據寫出來的順序對二叉樹進行線索化。

【問】接上,線索化的時候這麼亂,不知道線索改連到哪裏?

【答】每個結點左右各有一個指針,除了用於建樹的“藍色”線之外,我們只看紅色的線索這條線。每個結點只要是線索的部分,左邊就是指向排在該結點之前的那個結點,右邊就是指排在該節點之後的那個結點,這也就是爲什麼要先把遍歷的順序提前寫好的原因。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章