线索二叉树

目录

一、引出

代码实现:

二、中序线索二叉树

二叉树线索化

小结:

三、代码实现二叉树线索化

中序线索化:

先序线索二叉树

 后序略:(几乎同中序一样)

小结:

四、在线索二叉树中找前驱、后继

找后继

代码:

找前驱

代码:

先序线索二叉树

找后继:

找前驱:

后序线索二叉树

找后序前驱

找后继

小结:

下一篇:  树的顺序存储结构


一、引出

如何在普通二叉树中找到一个中序遍历中任意结点的前驱?

例如:中序遍历:DGBEAFC

要找F的前驱A要怎么做?

一种办法:首先从根结点开始遍历找到F结点,然后将p指针指向F,然后再次从根结点遍历,指针q指向当前访问结点,pre指向上一个被访问的结点,当q==p时pre指向的A就是F的前驱

 

 

代码实现:

//中序遍历

void InOrder(BiTree T){

if(T!=NULL){

InOrder(T->lchild);//递归遍历左子树

visit(T);

InOrder(T->rchild);//递归遍历右子树

}

}

 

辅助变量

BiTNode *p,*pre=NULL,*fina=NULL;//p是目标结点,pre前驱,final是最终结果

//访问结点q

void visit(BiTNode *q){

if(q==p){

final=pre;

}

else=pre=q;

}

 

二、中序线索二叉树

有n个结点的二叉树,有n+1个空链域!可用来记录前驱、后继的信息

 

二叉树线索化

前驱线索(由左孩子指针充当)

后继线索(由右孩子指针充当)

 

 

先序线索二叉树:按先序遍历进行线索化

 

后续线索二叉树同理

 

 

 

小结:

 

 

 

三、代码实现二叉树线索化

中序线索化:

//中序线索化二叉树T

//初始化时所有的线索标志要都为0

void CreateInThread(ThreadTree T){

pre=NULL;

if(T!=NULL){

InThread(T);

if(pre->rchild==NULL){//处理最后一个结点

pre->rtag=1;

}

}

}

void visit(ThreadNode *q){

if(q->lchild==NULL){//左子树为空,建立前驱线索

q->lchild=pre;

q->ltag=1;

}

if(pre!=NULL&&pre->rchild==NULL){//处理上一个结点的后继线索

pre->rchild=q;

pre->rtag=1;

}

pre=q;//指向下一个结点

}

//中序遍历二叉树,一边遍历一遍线索化

void InThread(ThreadTree T){

if(T!=NULL){

InThread(T->lchild);//

visit(T);//

InThread(T->rchild);//

}

}

 

 

先序线索二叉树

/*

先序遍历有点不一样,因为是先visit后访问左孩子

有可能在该结点的左指针线索化后指向上一个指针,

又这时要访问左结点就刚好访问到了上一个结点去,而产生死循环

所以在访问左孩子结点前得先判断tag是否等于0

visit不变

*/

void PreThread(ThreadTree T){

if(T!=NULL){

visit(T);

if(T->ltag==0){

PreThread(T->lchild);

}

PreThread(T->rchild);

}

}

void CreatPreThread(ThreadTree T){

pre=NULL;

if(T!=NULL){

PreThread(T);

//处理最后一个结点

if(pre->rchild==NULL)

pre->rtag=1;

}

}

 

 后序略:(几乎同中序一样)

由于后序线索化就是,后序遍历一遍,且是先处理左右孩子,所以不会产生死循环

 

 

小结:

 

 

 

四、在线索二叉树中找前驱、后继

 

找后继

在中序线索二叉树中找指定结点*p的中序后继next

分两种:

1、若p->rtag=1,则next=p->rchild

2、若p->ratg=0,则p必有右孩子

则情况2,需要中序遍历p的右子树,直到找到右子树最左下结点(不一定是叶结点哦!)

代码:

//找到以p为根的子树中,第一个被中序遍历的结点

ThreadNode *FirstNode(ThreadNode *p){

//循环找到最左下结点

while(p->ltag=0)p=p->lchild;

return p;

}

//在中序线索二叉树中找到结点p的后继结点

ThreadNode *NextNode(ThreadNode *p){

//右子树中最左下结点,如果该结点有右孩子

if(p->rtag==0)return FirstNode(p->rchild);

else return p->rchild; //rtag=1则直接返回后继线索

}

//利用这个特性对线索二叉树进行中序遍历

void _InOrder(ThreadNode *T){

//先找到子树的第一个最左结点,再不断的循环找中序后继结点并访问

for(ThreadNode *p=FirstNode(T);p!=NULL;p=NextNode(p)){

visit(p);

}

}

 

 

找前驱

分两种情况

1、p->ltag=1,则pre=p->lchild

2、p->ltag=0,则找p的左子树中最右下的结点

代码:

//找到以p为根的子树中,最后一个被中序遍历的结点

ThreadNode *LastNode(ThreadNode *p){

//循环找到最右下结点

while(p->rtag==0)p=p->rchild;

return p;

}

//在中序线索二叉树中找到结点p的前驱结点

ThreadNode *PreNode(ThreadNode *p){

//找该结点的左子树的最右下角结点

if(p->rtag==0)return LastNode(p->lchild);

else return p->lchild;

}

//利用这一特性,对中序线索二叉树进行逆向遍历

void RevInOrder(ThreadNode *T){

//先找到子树的的最右结点,再依次往前遍历

for(ThreadNode *p=LastNode(T);p!=NULL;p=PreNode(p)){

visit(p);

}

}

 

 

 

先序线索二叉树

找后继:

1、若p->rtag==1,则next=p->rchild

2、若tag==0,则:

有左则左,有右则右

 

找前驱:

1、tag=1则pre=p->lchild

2、tag=0则做不到

除非用从头遍历的土办法

或者该树是个三叉链表二叉树(有个指向父结点的指针)

 

第三种:简而言之就是,找p的兄弟子树的最后一个被遍历的(该子树右有右孩子就接着找,若还有左孩子也接着找)

如图:

 

第四种:就是p就是根结点,则p没有先序前驱

 

后序线索二叉树

找后序前驱

1、ltag==1,pre=p->lchild

2、ltag==0

 

找后继

1、rtag==1,next=p->rchild

2、rtag==0,则找不到,因为左右子树只可能是前驱

只能用土办法从头遍历

或则是三叉链表二叉树

第三种方法同上先序线索二叉树,但是是找右兄弟结点子树中第一个被访问的结点(左找完找右)

 

小结:

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值