线索二叉树

线索二叉树通过利用二叉链表的空指针域存储节点的前驱和后继信息,减少遍历时的重复工作。在遍历过程中线索化二叉树,可以节省查找前驱和后继的时间。节点增加ltag和rtag标志区分孩子指针和线索,防止遍历死循环。线索化后需重写遍历方法,前序、中序、后序线索化和遍历实现不同。
摘要由CSDN通过智能技术生成

图1

图1

先上一张图,如图1。我们可以发现二叉树中指针域并不是被充分利用了,有很多的 ^ ,也就是空指针域的存在。
对于一个有 n 个节点的二叉树,每个节点有左右孩子两个指针域,所以一共有 2n 个指针域。而 n 个节点的二叉树有 n - 1 条连线,所以存在 2n - ( n - 1 ) = n + 1 个空指针域。如图1所示的二叉树一共有10个节点,所以一共一11个空指针域。
这意味着空间的浪费,应该想办法将这些空间利用起来。

那么,怎么利用呢?

对于图1的二叉树的中序遍历是HDIBJEAFCG,我们可以知道节点B的前驱就是节点I,节点B的后继就是节点J,我们可以很清楚的知道一个节点的前驱和后继是哪一个。但是这是建立在二叉树被遍历的基础上。在二叉链表中,我们只知道每个节点指向其左右孩子的地址,并不知道某个节点的前驱和后继是谁。如果以后需要知道时,都必须先遍历一次。那为什么不在第一次遍历的时候就记住这些前驱和后继呢,这样将会节约大把的时间。线索二叉树就是这样诞生的。

综上所述

  • 利用二叉链表的空指针域,存放指向该节点在某种次序下前驱和后继节点的指针(这种指针叫做线索)。
  • 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树。根据线索性质的不同,线索二叉树可以分为前序线索二叉树中序线索二叉树后序线索二叉树三种。
  • 对二叉树以某种次序遍历使其变为线索二叉树的过程称作是线索化

图2

图2
如图2,在对二叉树中序遍历后,将所有的空指针域中的rchild指向它的后继节点。如 H的后继是D,J的后继是E,G的后继是null。

图3

图3
如图3,对二叉树中序遍历后,将所有空指针域中的lchilde指向他的前驱节点。如I的前驱是D,J的前驱是B,H的前驱是null。

图4

图4


问题来了?
我们怎么知道节点的指针域是指向它的孩子还是指向它的前驱和后继呢?比如图4中的E节点,lchild是指向左孩子J,而rchild是指向后继A。所以我们必须要区分lchild是指向左孩子还是前驱,rchild是指向右孩子还是后继。解决办法就是每个节点再增加两个标志域ltag和rtag,ltag和rtag存放布尔型变量。此时二叉树的节点如图5所示。
ltag为false时,lchild指向左孩子;ltag为true时,lchild指向前驱。
rtag为false时,rchild指向右孩子;rtag为true时,rchild指向后继。

图5:节点示意图

图5:节点示意图

注意:当二叉树被线索化后,原来直接递归遍历的那种方式就不能用了,否则会出现死循环。所以当线二叉树被线索化后,也需要重写遍历方法。另外,按前序、中序、后序的方式线索化和遍历二叉树实现是不同的。

代码实现

/**
 * 线索二叉树
 *
 * @author chenzhiyuan
 * @date 2019-10-04 10:49
 */
public class BinaryThreadTree {
   
    private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    private BinaryThreadNode root = null;
    // 定义一个全局变量,在线索化的时候始终指向当前被遍历节点的前一个节点
    private BinaryThreadNode pre = null;

    public static void main(String[] args) throws IOException {
   
        BinaryThreadTree binaryThreadTree = new BinaryThreadTree();
        binaryThreadTree.buildBiTree();

        // 先前序线索化,再遍历
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值