首页 > 其他分享 >数据结构 线索二叉树

数据结构 线索二叉树

时间:2022-12-13 15:07:40浏览次数:45  
标签:结点 遍历 指向 后继 链表 二叉树 数据结构 线索


一、线索二叉树的原理

    通过考察各种二叉链表,不管儿叉树的形态如何,空链域的个数总是多过非空链域的个数。准确的说,n各结点的二叉链表共有2n个链域,非空链域为n-1个,但其中的空链域却有n+1个。如下图所示。


数据结构 线索二叉树_头结点

    因此,提出了一种方法,利用原来的空链域存放指针,指向树中其他结点。这种指针称为线索。

    记ptr指向二叉链表中的一个结点,以下是建立线索的规则:

    (1)如果ptr->lchild为空,则存放指向中序遍历序列中该结点的前驱结点。这个结点称为ptr的中序前驱;

    (2)如果ptr->rchild为空,则存放指向中序遍历序列中该结点的后继结点。这个结点称为ptr的中序后继;

    显然,在决定lchild是指向左孩子还是前驱,rchild是指向右孩子还是后继,需要一个区分标志的。因此,我们在每个结点再增设两个标志域ltag和rtag,注意ltag和rtag只是区分0或1数字的布尔型变量,其占用内存空间要小于像lchild和rchild的指针变量。结点结构如下所示。


数据结构 线索二叉树_线索化_02

    其中:

    (1)ltag为0时指向该结点的左孩子,为1时指向该结点的前驱;

    (2)rtag为0时指向该结点的右孩子,为1时指向该结点的后继;

    (3)因此对于上图的二叉链表图可以修改为下图的养子。


数据结构 线索二叉树_结点_03

二、线索二叉树结构实现

    二叉线索树存储结构定义如下:


  线索化的实质就是将二叉链表中的空指针改为指向前驱或后继的线索。由于前驱和后继信息只有在遍历该二叉树时才能得到,所以,线索化的过程就是在遍历的过程中修改空指针的过程。

    中序遍历线索化的递归函数代码如下:


上述代码除了//===之间的代码以外,和二叉树中序遍历的递归代码机会完全一样。只不过将打印结点的功能改成了线索化的功能。

    中间部分代码做了这样的事情:

因为此时p结点的后继还没有访问到,因此只能对它的前驱结点pre的右指针rchild做判断,if(!pre->rchild)表示如果为空,则p就是pre的后继,于是pre->rchild = p,并且设置pre->rtag = Thread,完成后继结点的线索化。如图:


数据结构 线索二叉树_线索化_04



    if(!p->lchild)表示如果某结点的左指针域为空,因为其前驱结点刚刚访问过,赋值了pre,所以可以将pre赋值给p->lchild,并修改p->ltag = Thread(也就是定义为1)以完成前驱结点的线索化。


数据结构 线索二叉树_头结点_05

    

    完成前驱和后继的判断后,不要忘记当前结点p赋值给pre,以便于下一次使用。

    

    有了线索二叉树后,对它进行遍历时,其实就等于操作一个双向链表结构。


数据结构 线索二叉树_头结点_06

    和双向链表结点一样,在二叉树链表上添加一个头结点,如下图所示,并令其lchild域的指针指向二叉树的根结点(图中第一步),其rchild域的指针指向中序遍历访问时的最后一个结点(图中第二步)。反之,令二叉树的中序序列中第一个结点中,lchild域指针和最后一个结点的rchild域指针均指向头结点(图中第三和第四步)。这样的好处是:我们既可以从第一个结点起顺后继进行遍历,也可以从最后一个结点起顺前驱进行遍历。


数据结构 线索二叉树_结点_07

    遍历代码如下所示。

说明:




    (1)代码中,p = t->lchild;意思就是上图中的第一步,让p指向根结点开始遍历;


    (2)while(p != t)其实意思就是循环直到图中的第四步出现,此时意味着p指向了头结点,于是与t相等(t是指向头结点的指针),结束循环,否则一直循环下去进行遍历操作;


    (3)while(p-ltag == Link)这个循环,就是由A->B->D->H,此时H结点的ltag不是link(就是不等于0),所以结束此循环;


    (4)然后就是打印H;


    (5)while(p->rtag == Thread && p->rchild != t),由于结点H的rtag = Thread(就是等于1),且不是指向头结点。因此打印H的后继D,之后因为D的rtag是Link,因此退出循环;


    (6)p=p->rchild;意味着p指向了结点D的右孩子I;


    (7).....,就这样不断的循环遍历,直到打印出HDIBJEAFCG,结束遍历操作。




    从这段代码可以看出,它等于是一个链表的扫描,所以时间复杂度为O(n)。


    由于充分利用了空指针域的空间(等于节省了空间),又保证了创建时的一次遍历就可以终生受用后继的信息(意味着节省了时间)。所以在实际问题中,如果所用的二叉树需要经过遍历或查找结点时需要某种遍历序列中的前驱和后继,那么采用线索二叉链表的存储结构就是非常不错的选择。




标签:结点,遍历,指向,后继,链表,二叉树,数据结构,线索
From: https://blog.51cto.com/u_14682436/5934129

相关文章

  • 二叉树的最大深度
    题目地址(104.二叉树的最大深度)​​https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/​​题目描述给定一个二叉树,找出其最大深度。二叉树的深度为根节点......
  • 543. 二叉树的直径
    题目给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过也可能不穿过根结点。分析思路和算树最大高度的那题......
  • 对前端数据结构与算法的研究----------------引用
         1.递归      递归就是自己调自己,递归在前端里面算是一种比较常用的算法。假设现在有一堆数据要处理,要实现上一次请求完成了,才能去调下一个请求。一......
  • 复杂数据结构的解析
    <!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metahttp-equiv="X-UA-Compatible"content="IE=edge"/><metaname="viewport"co......
  • Java数据结构之栈和队列
    原文链接:https://blog.csdn.net/fear_wolf/article/details/127459611文章目录一、栈(Stack)(一)概念(二)栈的使用(三)栈的模拟实现(四)问题思考1.栈,虚拟机栈,栈帧有什么区别?2.单链......
  • 数据结构之数组
    1.数组实现数组的特点:内存是连续的,即物理地址是连续的。优点:随机访问的时间复杂度为O(1);末尾位置增加元素的时间复杂度为O(1);访问元素前后相邻位置的元素非常方便......
  • 我花了一夜用数据结构给女朋友写个H5走迷宫游戏
    文章目录​​起因​​​​分析​​​​画线(棋盘)​​​​画迷宫​​​​方块移动​​​​结语​​先看效果图(在线电脑尝试地址http://biggsai.com/maze.html):起因又到深......
  • 平衡二叉树(java版)
    题目描述:标签:树深度优先搜索递归给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点的左右两个子树的高度差的绝对值......
  • day35_0106.从中序与后序遍历序列构造二叉树0105. 前序+中序构造二叉树
    0106.从中序与后序遍历序列构造二叉树前序+中序构造二叉树[106中序+后序构造二叉树]做过简答题但没编过代码以下均是复制粘贴递归代码的思路----三部曲......
  • Java实现二叉树的先序、中序、后序、层序遍历(递归+非递归方法),附带自己深入浅出的讲解
     二叉树(Binarytree)是树形结构的一个重要类型,也一种非常重要的数据结构,更是算法题中高频出现的知识点,不管是为了应付工作还是面试,都有必要深度学习一下。二叉树有多种遍......