非线性表——线索二叉树

8.5线索二叉树

8.5.1基本概念

每个结点增加两个指针域,指示遍历时得到的前驱和后继。

但是,存储密度大大降低。

在n个结点的二叉链表中必定存在有n+1个空链域,

利用空链域来存放结点的前驱、后继信息。

同时结点增加两个标志域LTag,RTag:  

若LTag=0,LChild域指向左孩子;

若LTag=1,LChild域指向其前驱。  

若RTag=0,RChild域指向右孩子;  

若RTag=1,RChild域指向其后继。

当二叉树以某种次序遍历

使其变为线索二叉树的过程

叫做线索化,

指向结点前驱和后继的指针,称为线索。

结点定义:

typedef  struct BiThrNode{
    int  data;
    int  Ltag, Rtag;
    struct node *lchild, *rchild;
} BiThrNode,* BiThrTree;

8.5.2先序线索二叉树

结点x的后继:

Rtag=1:

Rchild指示其后继;

Rtag=0:  

A)若x有左孩子,后继为其左孩子;  

B)若x无左孩子有右孩子,后继为其右孩子。

例:

先序序列:ABCDE

8.5.3中序线索二叉树

结点x的后继:

Rtag=0://有右孩子,根据左根右的顺序,先访问最左的子孙

其后继为中序遍历其右子树时第一个被访问的结点,即其右子树最左下的结点。

Rtag=1:

Rchild指示其后继;

中序序列:BCAED

 在中序线索二叉树中

查找p的后继结点,并用succ指针返回结果

//此代码用于左右孩子和左右tag域 皆已经确定,即已经完成线索化的

void InSucc(BiTNode * p,BiTNode * succ){
    if(p->Rtag==1) succ=p-> RChild; 
    else{   /* 在p的右子树中查找最左下的结点*/
        q=p->RChild; 
        while(q->Ltag==0) q=q->LChild;
        succ=q; 
    } 
}

在中序线索二叉树中

查找p的前驱结点,并用pre指针返回结果

//此代码用于左右孩子和左右tag域 皆已经确定,即已经完成线索化的

void InPre(BiTNode * p,BiTNode * pre){
    if(p->Ltag==1)//p结点没有左孩子 
        pre=p->LChild;//因为没有左孩子的结点左孩子存放的就是则p的前驱
    else{   /* 在p的左子树中查找最右下的结点*/
        q=p->LChild; 
        while(q->Rtag==0) q=q->RChild;
        pre=q; 
    } 
}

8.5.4后序线索二叉树

后序序列:CBEDA

   结点x的后继:

Rtag=1:Rchild指示其后继;

Rtag=0:  

A)若x为根,无后继;  

B)若x为其双亲的右孩子或为其双亲的左孩子且其双亲无右子树,其后继即为双亲结点;  

C)若x为其双亲的左孩子且其双亲有右子树,其后继为遍历其双亲右子树时第一个被访问的结点,即其双亲右子树最左下的结点。

8.5.5带头结点的线索二叉树

头结点的:

ltag=0, lchild指向根结点 ,

rtag=1, rchild指向遍历序列中最后一个结点 。

遍历序列中第一个结点的lchild域指向头结点 ,

遍历序列中最后一个结点的rchild域指向头结点。

8.5.5.1带头结点的中序线索二叉树

中序序列:BCAED

//中序遍历的线索化
NODE * inthread(NODE * bt){//bt是根节点
  t=(NODE *)malloc(sizeof(NODE));//t是头结点
  t->ltag=0;  t->rtag=1;  t->rchild=t;//现在还不知道遍历的最后一个节点是哪个,t的右孩子暂时指向自己
  if(!bt)  t->lchild=t;//空树
  else { 
    pre=t;  t->lchild=bt;    

    inthreading(bt);  

    //线索化完了之后
    pre->rtag=1; pre->rchild=t;//遍历序列中最后一个结点的rchild域指向头结点。
    t->rchild=pre;//t的右孩子可以确定了,为当前的pre结点

  }
  return t;
}
//线索化的过程

void  inthreading( NODE * p ) {
  if( p ) { 
    inthreading( p->lchild );   
    if( !p->lchild )//没有左孩子  
      {  p->ltag=1;   p->lchild=pre; }
    if( !pre->rchild )   
      { pre->rtag=1;   pre->rchild=p; }
    pre=p;
    inthreading( p->rchild );
  }
}

//对已经线索化的树进行中序遍历,并输出中序遍历结果
void Inorder_Thr( NODE *t )//t是该树的头结点
 { 
    p=t->lchild;
    while( p!=t ) 
    { 
        while( p->ltag==0 )  p=p->lchild; 
        printf(p->data );
        while( p->rtag==1 && p->rchild!=t )
           { p=p->rchild;  printf(p->data ); }
        p=p->rchild;
    }
}

例题:

下列线索二叉树中(用虚线表示线索)符合后序线索树定义的是______。

答案:D

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值