前面一篇部落格講述了二叉樹的建立和遍曆,無論是前序還是中序或是後序,只不過是訪問資料的順序不一樣,是為了訪問二叉樹而人為化的一種鏈式“形”,突出的是訪問的內在聯絡。同樣地,線索化的二叉樹也是,在前驅和後繼之間建立起一種聯絡,從而使訪問特別快,特別方便。
線索化二叉樹是在二叉樹的序(前,中,後)的基礎上建立起來的。其關鍵是利用閒置lchild和rchild儲存其前驅和後繼,對於度為2 的節點,lchild和rchild!=null,已經儲存了相關資訊。所以線索化二叉樹時,就是找出lchild和rchild(==null)的節點,然後使lchild和rchild分別指向前驅和後繼。為了遍曆線索化二叉樹時,我們能有效區分lchild(rchild)是儲存了左子樹(右子樹)還是儲存了前驅(後繼),我們可以增加兩個有效標誌位lfag,rflag。具體原理見如下:
仿造普通的”線索“的表示,箭頭線段分別表示,前驅和後繼,注意:箭頭線段的節點沒有左子樹(右子樹)。
採用的節點資料結構:
typedef struct Tnode{ char data; Tnode* lchild; Tnode* rchild; bool lflag; bool rflag;}
我採用前序建立二叉樹,前序走訪,中序線索化二叉樹,然後線索遍曆二叉樹,共四個函數。
代碼如下:
#include<iostream>using namespace std;typedef struct Tnode{ char data; Tnode* lchild; Tnode* rchild; bool lflag; bool rflag;} BiTnode,* BiTree;//前序建立二叉樹void CreateBiTree(BiTree* T){ char inputChar; cin>>inputChar; //空子樹 if(inputChar=='#') { *T=0; return ; } else { (*T)=(BiTree)malloc(sizeof(BiTnode)); if(!(*T)) throw "Invalid Address"; else { (*T)->data=inputChar; (*T)->lflag=0; (*T)->rflag=0; CreateBiTree(&((*T)->lchild)); CreateBiTree(&((*T)->rchild)); } }}//前序走訪二叉樹void preTraverse(BiTree T){ if(T) { cout<<T->data<<","; preTraverse(T->lchild); preTraverse(T->rchild); }}//中序二叉樹線索化void inThreadedBiTree(BiTree T,BiTree * h ){ if(T!=NULL) { inThreadedBiTree(T->lchild,h); if(T->lchild==NULL) { T->lchild=*h; T->lflag=1; } if(*h!=NULL&&((*h)->rchild==NULL)) { (*h)->rchild=T; (*h)->rflag=1; } *h=T;//採用二級指標的意義就在於此,為了指向T,T一級指標,這樣可以省空間 inThreadedBiTree(T->rchild,h); }}//線索遍曆二叉樹void inThreadTraverse(BiTree T){ BiTree h; if(T==NULL)return; h=T; while(h->lflag==0)h=h->lchild; cout<<h->data<<","; while(h->rchild!=NULL) { if(h->rflag==1) h=h->rchild; else { h=h->rchild; while((h->lflag==0)&&(h->lchild!=NULL)) h=h->lchild; } cout<<h->data<<","; }}int main(){BiTree* T=(BiTree*)malloc(sizeof(BiTree*));; CreateBiTree(T);cout<<"前序輸出二叉樹:"<<endl; preTraverse(*T);BiTree h=NULL; inThreadedBiTree( *T, &h ); cout<<endl<<"線索遍曆:";inThreadTraverse(*T); return 0; }
註:其他方法(前序線索和後序線索)類似,明白原理即可,要用再查書。可見線索化二叉樹,只是引入了一種遍曆的方式而已,其帶來的劣勢是:增加了空間。
測試結果:按開始給出的:輸入 ABC###DE##F##
分兩種情況,rchild!=null,即不存在右子樹的,按後繼鏈尋找,反之,按原遍曆順序尋找,直到末尾點,讀者可按運行結果筆畫一下。