線索二叉樹
基本概念:
n個結點的二叉鏈表中共有2n個鏈域,但只有n-1個有用的非空鏈域,其余n+1個是空的,利用這n+1個空鏈域來存放遍歷過程中結點的前驅和后繼;規定:若結點有左子樹,則其LChild指向左孩子,否則LCHild指向前驅;若結點有右子樹,則其RChild域指向右孩子,否則指向后繼。
Ltag=0,CHild指向左孩子;Ltag=1,CHild指向遍歷的前驅
Rtag=0,RHild指向左孩子;Rtag=1,RHild指向遍歷的前驅
指向前驅和后繼的指針稱為線索。以這種結構組成的二叉鏈表作為二叉樹的存儲結構,稱為線索鏈表。對二叉樹以某種次序進行遍歷並且加上線索的過程稱為線索化。線索化的二叉樹稱為線索二叉樹。
算法思想:
- 中序線索化采用中序遞歸遍歷算法框架
- 加線索的操作就是訪問結點的操作
- 加線索操作需要利用剛訪問的結點與當前節點的關系,因此設置一個指針pre,始終記錄剛訪問過的結點,操作如下
a.如果當前遍歷結點root的左子域為空,左子域指向pre;
b.如果前驅pre的右子域為空,則讓右子域指向當前遍歷結點root;
c.為下次做准備,訪問當前結點root作為下一個訪問結點的前驅pre
廢話不多說了,直接上代碼:
#include <stdio.h> #include <stdlib.h> typedef struct Tree { int data,Ltag,Rtag;//數據,左右標志 struct Tree *LChild,*RChild;//左右孩子指針域 }Tree,*Trees; Trees pre=NULL; void InitTree(Trees *boot)//初始化二叉樹,只有一個根節點,無左右孩子 { *boot=(Trees)malloc(sizeof(Tree)); (*boot)->LChild=(*boot)->RChild=NULL; (*boot)->Ltag=(*boot)->Rtag=0; } void CreateTree(Trees &boot)//創建二叉樹,具體操作參考上一篇《樹與二叉樹》 { int ch; scanf("%d",&ch); if(ch==0) boot=NULL; else { boot=(Trees)malloc(sizeof(Tree)); boot->data=ch; boot->LChild=boot->RChild=NULL; boot->Ltag=boot->Rtag=0; CreateTree(boot->LChild); CreateTree(boot->RChild); } } //添加線索 void InThread(Trees &boot) { if(boot!=NULL) { InThread(boot->LChild);//線索化左子樹 if(boot->LChild==NULL) { boot->Ltag=1; boot->LChild=pre;//置前驅線索 } if(pre!=NULL&&pre->RChild==NULL) { pre->RChild=boot; pre->Rtag=1; } pre=boot;//當前訪問節點為下一個訪問節點的前驅 InThread(boot->RChild);//線索化右子樹 } } Trees InOrderThread(Trees &rt)//建頭結點 { Trees thrt; if(!(thrt=(Trees)malloc(sizeof(Tree)))) { printf("頭結點創建失敗.\n"); exit(1); } thrt->Ltag=0;//等於零指向左孩子 1 thrt->Rtag=1;//等於一指向遍歷的前驅 2 thrt->RChild=thrt;//右回指針,指向自己(頭結點) 3 if(!rt) thrt->LChild=thrt;//若二叉樹為空,建立左回指針(也指向頭結點) else { thrt->LChild=rt;//rt==boot,也就是二叉樹的根 pre=thrt;//pre指向頭結點 InThread(rt);//為二叉樹加線索 pre->RChild=thrt;//同上1 pre->Rtag=1;//同上2 thrt->RChild=pre;//同上3 } return thrt; } //中序找前驅 void InPre(Trees boot) { Trees q=NULL; if(boot->Ltag==1) pre=boot->LChild; else { for(q=boot->LChild;q->Rtag==0;q=q->RChild) pre=q; } if(pre) printf("中序找到的前驅為:%d\n",pre->data); else printf("無前驅.\n"); } //中序找后繼 void InNext(Trees boot) { Trees q=NULL; if(boot->Rtag==1) pre=boot->RChild; else { for(q=boot->RChild;q->Ltag==0;q=q->LChild) pre=q; } if(pre) printf("中序找到的后繼為:%d\n",pre->data); else printf("中序遍歷無后繼.\n"); } //中序遍歷序線索樹上的第一個結點 Trees InFirst(Trees boot) { Trees p=boot; if(!p) return NULL; while(p->Ltag==0) p=p->LChild; return p; } //中序遍歷線索二叉樹 void TInOrder(Trees &thrt) { Trees p; p=thrt->LChild; while(p!=thrt) { while(p->Ltag==0) p=p->LChild; printf("%d ",p->data); while(p->Rtag==1&&p->RChild!=thrt) { p=p->RChild; printf("%d ",p->data); } p=p->RChild; } printf("\n"); } int main() { Trees boot=NULL; printf("創建二叉樹,輸入零結束:\n"); CreateTree(boot); Trees thrt;//頭結點 thrt=InOrderThread(boot); TInOrder(thrt);//中序遍歷線索二叉樹 InPre(boot);//中序找前驅 InNext(boot);//中序找后繼 Trees bt=InFirst(boot);//中序遍歷序線索樹上的第一個結點 printf("中序遍歷序線索樹上的第一個結點為:%d\n",bt->data); return 0; }
結果: