线索化二叉树
线索二叉树
基本概念:
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; }
结果: