数据结构历年考研真题对应知识点(线索二叉树)

目录

5.3.2线索二叉树

1.线索二叉树的基本概念

【后序线索二叉树的定义(2010)】

2.中序线索二叉树的构造

【中序线索二叉树中线索的指向(2014)】

3.中序线索二叉树的遍历

4.先序线索二叉树和后序线索二叉树

【后序线索二叉树中线索的指向(2013)】


5.3.2线索二叉树

1.线索二叉树的基本概念

后序线索二叉树的定义(2010)】

传统的二叉链表存储仅能体现一种父子关系,不能直接得到结点在遍历中的前驱或后继。前面提到,在含n个结点的二叉树中,有n+1个空指针。这是因为每个叶结点都有2个空指针,每个度为1的结点都有1个空指针,空指针总数为2n0+n1,又n0=n2+1,所以空指针总数为n0+n1+n2+1=n+1(n0、n1、n2分别表示度为0、1、2的结点个数

由此设想能否利用这些空指针来存放指向其前驱或后继的指针?这样就可以像遍历单链表那样方便地遍历二叉树。

引入线索二叉树正是为了加快查找结点前驱和后继的速度。
规定:若无左子树,令 lchild指向其前驱结点;若无右子树,令 rchild 指向其后继结点。

如图 5.17所示,还需增加两个标志域,以标识指针域指向左(右)孩子或前驱(后继)。

 

线索二叉树的存储结构描述如下:

typedef struct ThreadNode{
    ElemType data;                      //数据元素
    struct ThreadNode *lchild,*rchild;  //左、右孩子指针
    int ltag,rtag;                      //左、右线索标志
}ThreadNode,*ThreadTree;

以这种结点结构构成的二叉链表作为二叉树的存储结构,称为线索链表,其中指向结点前驱和后继的指针称为线索。加上线索的二叉树称为线索二叉树。

2.中序线索二叉树的构造

中序线索二叉树中线索的指向(2014)】

二叉树的线索化是将二叉链表中的空指针改为指向前驱或后继的线索。而前驱或后继的信息只有在遍历时才能得到,因此线索化的实质就是遍历一次二叉树

以中序线索二叉树的建立为例。附设指针 pre 指向刚刚访问过的结点,指针p指向正在访问的结点,即 pre 指向p的前驱。在中序遍历的过程中,检査p的左指针是否为空,若为空就将它指向 pre;检査 pre 的右指针是否为空,若为空就将它指向p,如图 5.18 所示。

通过中序遍历对二叉树线索化的递归算法如下:

void InThread(ThreadTree &p,ThreadTree &pre){
    if(p!=NULL){
        InThread(p->lchild,pre);        //递归,线索化左子树
        if(p->lchild==NULL){            //当前结点的左子树为空
            p->lchild=pre;              //建立当前结点的前驱线索
            p->ltag=1;
         }
         if(pre!=NULL&&pre->rchild==NULL){ //前驱结点非空且其右子树为空
            pre->rchild=p;                 //建立前驱结点的后继线索
            pre->rtag=1;
         }
            pre=p;                    //标记当前结点成为刚刚访问过的结点
            InThread(p->rchild,pre);  //递归,线索化右子树
    }
}

通过中序遍历建立中序线索二叉树的主过程算法如下:

void CreateInThread(ThreadTree T){
    ThreadTree pre=NULL;
    if(T!=NULL){            //非空二叉树,线索化
        InThread(T pre);    //线索化二叉树
        pre->rchild=NULL;   //处理遍历的最后一个结点
        pre->rtag=l;
    }
}

为了方便,可以在二叉树的线索链表上也添加一个头结点,令其lchild域的指针指向二叉树的根结点,其 rchild 域的指针指向中序遍历时访问的最后一个结点;

令二叉树中序序列中的第一个结点的 lchild域指针和最后一个结点的 rchild 域指针均指向头结点。

这好比为二叉树建立了一个双向线索链表,方便从前往后或从后往前对线索二叉树进行遍历,如图 5.19 所示。

3.中序线索二叉树的遍历

中序线索二叉树的结点中隐含了线索二叉树的前驱和后继信息。在对其进行遍历时,只要先找到序列中的第一个结点,然后依次找结点的后继,直至其后继为空。

中序线索二叉树中找结点后继的规律是:若其右标志为“1”,则右链为线索,指示其后继,否则遍历右子树中第一个访问的结点(右子树中最左下的结点)为其后继。

不含头结点的线索二叉树的遍历算法如下。

1) 求中序线索二叉树的中序序列下的第一个结点:

ThreadNode *Firstnode(ThreadNode*p){
    while(p->ltag==0) p=p->lchild;     //最左下结点(不一定是叶结点)
    return p;
}

2) 求中序线索二叉树中结点p在中序序列下的后继:

ThreadNode *Nextnode(ThreadNode*p){
    if(p->rtag==0) return Firstnode(p->rchild);  //右子树中最左下结点
    else return p->rchild;      //若rtag==1则直接返回后继线索
}

请读者自行分析并完成求中序线索二叉树的最后一个结点和结点p前驱的运算

3) 利用上面两个算法,可写出不含头结点的中序线索二叉树的中序遍历的算法:

void Inorder(ThreadNode *T){
    for(ThreadNode *p=Firstnode(T); p!=NULL; p=Nextnode(p))
        visit(p);
}

4.先序线索二叉树和后序线索二叉树

后序线索二叉树中线索的指向(2013)】

在后序线索二叉树中找结点的后继较为复杂,可分三种情况

①若结点x是二叉树的根,则其后继为空;

②若结点x是其双亲的右孩子,或是其双亲的左孩子且其双亲没有右子树,则其后继即为双亲;

③若结点x是其双亲的左孩子,且其双亲有右子树,则其后继为双亲的右子树上按后序遍历列出的第一个结点。

图5.20(c)中找结点B的后继无法通过链域找到,可见在后序线索二叉树上找后继时需知道结点双亲,即需采用带标志域的三叉链表作为存储结构

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心碎烤肠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值