1. 程式人生 > >資料結構--樹--線索二叉樹(中序,前序,後序)

資料結構--樹--線索二叉樹(中序,前序,後序)

線索二叉樹

在遍歷二叉樹的時候,會有許多空指標域,這些空間不儲存任何事物,白白浪費了記憶體的資源。
那麼在做遍歷的時候,提前記錄下每個結點的前驅和後繼,這樣就更加節約了時間。
                 [ 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;
}

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


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


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

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

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

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