A與B的對話之線索二叉樹
A:什麼是線索二叉樹?
B:先彆著急,你知道二叉樹的定義的儲存結構是什麼嗎?
A:當然知道,就是包含一個值域和兩個指標域的結構體,下圖所示
typedef struct node
{
char data;
struct node *left,*right;
}Tree
B:是的,是這樣的,我們可以從程式碼中看出,我們可以通過left和right指標來找到一個結點的左右孩子,對嗎?那如果我們想要找到一個結點的前驅和後繼該怎麼辦呢?
A:很容易找到左右孩子,嗯?前序和後繼?這個是什麼意思?
B:我們知道一個樹有三種遍歷,前後中,比如一個樹的前序遍歷是ABC,我們很容易看出B的前驅結點時A,B的後繼結點是C,當我們遍歷整個二叉樹時,很容易找出某個結點的前驅和後繼,那麼如果我需要直接讓你用程式碼找出一個結點的前驅和後繼,你該怎麼辦呢?
A:新增新的指標嗎?
B:不用不用,你想想我們建立一棵有n個結點的樹時,建立了多少指標?
A:一個結點兩個指標,當然是2n個指標
B:我們一共用了多少個指標呢?
A:n個結點的二叉樹的一共有n-1條分支,那麼我們就用了n-1個指標,還有2n-(n-1)個指標沒有使用
B:對了,我們就可以利用著n+1個指標來指向一個結點的前驅和後繼,而且還利用了空間
A:我有點糊塗了,那應該怎麼做呢?
B:因為我們的結點本生就具有兩個指標,我們如何知道它的左右孩子是指向前驅還是後繼呢?我們在原有的基礎上,加上ltga和rtag來判斷左右指標的指向
ltag==0時代表該結點的left指標指向的是左孩子
ltag==1時代表該結點的left指標指向的是前驅結點
同理可知rtag
A:我明白了!那我們該如何實現呢
B:我們在遍歷二叉樹的時候就會知道結點的前驅,那時候我們就可以給ltag和rtag進行賦值
A:我通過中序遍歷來給ltag和rtag賦值
#include <iostream> #include<stdlib.h> using namespace std; typedef struct node { char data; struct node *left,*right; int ltag,rlag; }ThreadTree;//線索二叉樹 ThreadTree *create()//遞迴建立二叉樹 { ThreadTree *t=(ThreadTree *)malloc(sizeof(ThreadTree)); char a; cin>>a; if(a=='#') t=NULL; else{ t->data=a; t->left=t->right=NULL; t->left=create(); t->right=create(); } return t; } void Zhongxu(ThreadTree *t)//中序線索二叉樹 { ThreadTree *pre;//代表後繼 if(t) { Zhongxu(t->left); if(t->left==NULL)//左是前驅 { t->ltag=1; t->left=pre; } if(pre->right==NULL)//右是後繼 { pre->rlag=1; pre->right=t; } pre=t; cout<<t->data; Zhongxu(t->right); } } int main() { ThreadTree *t; t=create();//建立二叉樹 Zhongxu(t);//中序遍歷二叉樹 }
A:這就是線索二叉樹的過程,現在你明白什麼是線索二叉樹了嘛
B:明白了!線索二叉樹就是利用二叉樹空閒的指標,將它指向結點的前驅後者後繼,這樣就很快可以找到一個結點的前驅和後繼
A:Yes,就是這樣。不要忘記了,線索二叉樹有三種結構哦~