1. 程式人生 > >詳解線索二叉樹

詳解線索二叉樹

遍歷二叉樹是對非線性結構進行線性化操作,在得到的訪問序列中,每個結點都只有一個直接前驅和一個直接後繼。(除區頭尾兩個結點)

引入線索二叉樹可以加快查詢前驅與後繼結點的速度,實質就是將二叉連結串列中的空指標改為指向前驅或後繼的線索,線索化就是在遍歷中修改空指標。

通常規定:對某一結點,若無左子樹,將lchild指向前驅結點;若無右子樹,將rchild指向後繼結點。

還需要設定左右兩個tag,用來標記當前結點是否有子樹。

若ltag==1,lchild指向結點前驅;若rtag==1,rchild指向結點後繼。

線索二叉樹的儲存結構如下:

typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag;
}ThreadNode, *ThreadTree;

首先建立一棵二叉樹,預設輸入是按照先序遍歷:

void CreateThreadTree(ThreadTree &T)
{
char c;
cin >> c;
if('#' == c)
T = NULL;
else{
T = new ThreadNode;
T->data = c;
CreateThreadTree(T->lchild);
CreateThreadTree(T->rchild);
}
}

現在我們通過中序遍歷建立中序線索二叉樹,即對給定的二叉樹,遞迴進行線索化操作:

void CreateInThread(ThreadTree T)
{
ThreadTree pre = NULL;
if(T != NULL)
{
InThread(T, pre);               //對非空二叉樹線索化
pre->rchild = NULL;             //處理遍歷的最後一個結點
pre->rtag = 1;
}
}

其中通過中序遍歷對二叉樹線索化的遞迴演算法為:

void InThread(ThreadTree &p, ThreadTree &pre)    //pre始終指向中序遍歷時上一個剛剛訪問過的結點;
{
if(p != NULL)
{
InThread(p->lchild, pre);          //遞迴線索化左子樹;
if(p->lchild == NULL)           //左子樹為空,建立前驅線索;
{
p->lchild = pre;
p->ltag = 1;
}
if(pre != NULL && pre->rchild == NULL) //建立前驅結點的後繼線索;
{
pre->rchild = p;
pre->rtag = 1;
}
pre = p;               //標記當前結點成為剛剛訪問過的結點;
InThread(p->rchild, pre);       //遞迴線索化右子樹;
}
}

線索二叉樹已經構造完成。現在利用線索二叉樹,可以實現二叉樹遍歷的非遞迴演算法。以中序遍歷為例:

要實現中序遍歷,可以先求出中序線索二叉樹的中序序列中第一個結點,然後呼叫求某個結點的後繼結點演算法,直到遍歷完成。

求中序線索二叉樹的中序序列中第一個結點演算法:

ThreadNode *FirstNode(ThreadNode *p)
{
while(p->ltag != 1)         //如果有左孩子,迭代至左孩子
p = p->lchild;
return p;
}

求中序線索二叉樹中序序列中某個結點的後繼結點演算法:

ThreadNode *NextNode(ThreadNode *p)
{
if(p->rtag != 1)            //如果有右孩子,則該結點的後繼結點為該結點右子樹在中序序列中的第一個結點;
return FirstNode(p->rchild);
else
return p->rchild;         //如果沒有右孩子,直接返回後繼結點;
}

最後,實現中序遍歷:

void InOrderThread(ThreadNode *T)
{
for(ThreadNode *p = FirstNode(T); p!= NULL; p = NextNode(p))
{
cout << p->data << " ";
}
}

主函式如下:

int main()
{
ThreadTree T;            //定義一顆二叉樹;
CreateThreadTree(T);        //構造二叉樹;
CreateInThread(T);         //對二叉樹線索化;
InOrderThread(T);         //對線索二叉樹實現非遞迴的中序遍歷;
return 0;
}

執行結果如圖所示: