数据结构与算法:树 线索化二叉树(中,前,后序)

Posted 史大拿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构与算法:树 线索化二叉树(中,前,后序)相关的知识,希望对你有一定的参考价值。

Tips: 采用java语言,关注博主,底部附有完整代码

工具:IDEA

本系列介绍的是数据结构:

这是第3篇目前计划一共有11篇:

  1. 二叉树入门
  2. 顺序二叉树
  3. 线索化二叉树 本篇
  4. 堆排序
  5. 赫夫曼树(一)
  6. 赫夫曼树(二)
  7. 赫夫曼树(三)
  8. 二叉排序树(BST)
  9. 平衡二叉排序树AVL
  10. 2-3树,2-3-4树,B树 B+树 B*树 了解
  11. 数据结构与算法:树 红黑树 (十一)

敬请期待吧~~

高光时刻

中序线索化前序线索化后续线索化

回顾

先来回顾一下中序遍历

每一个结点有2个对象,最终导致叶子结点就有所浪费

当前一共有6个元素,分别是 [1,3,6,8,10,14], 最终就会导致有7个对象浪费(null)掉

出现问题

线索化二叉树就是尽量少浪费对象,那么空对象如何处理呢?

如何解决

先来看完整流程图,在逐步分析:

最终结果图:

中序线索化二叉树 就是按照中序遍历的结果将

  • 叶子结点
  • 单子结点

按照中序的排列连接起来

当前中序遍历结果是 [8, 3, 10, 1, 14, 6]

以10举例,10是叶子结点,那么就按照中序遍历10左右的结点连接起来

  • 10左侧的值3 当作10的左子结点
  • 10右侧的值1 当作10的右子结点

因为10是叶子结点,如果连接起来的也叫左子结点和右子结点容易和真正有左子/右子结点的结点搞混

所以在线索化中,如果是通过连接连起来的就叫做前驱结点后继结点

例如 :

  • 10的前驱结点是3

  • 10的后继结点是1

  • 8的前驱结点是null

  • 8的后继结点是3

  • 3的左子结点是8

  • 3的右子结点是10

先按照树状图来看结点,如果他有左子结点或者右子结点,那么就按照排列好的顺序来,就是前驱结点和后继结点

直接来看一眼代码

中序

中序线索化

结点:

public class HeroNode 
    public int id;
    public String name;
    // 左子结点
    public HeroNode leftNode;
    // 右子结点
    public HeroNode rightNode;

    // [0 左子节点] [1 前驱节点]
    public int leftType;

    // [0 右子节点] [1 后继节点]
    public int rightType;

    public HeroNode(int id, String name) 
        this.id = id;
        this.name = name;
    

    @Override
    public String toString() 
        return "HeroNode" +
                "id=" + id +
                ", name='" + name + '\\'' +
                ", leftType='" + leftType + '\\'' +
                ", rightType='" + rightType + '\\'' +
                '';
    

Tree:

public class ThreadedBinaryTree 
   // root 结点
   private final HeroNode root;

    public ThreadedBinaryTree(HeroNode root) 
        this.root = root;
    
  
   public void threadedCenter() 
        threadedCenter(root);
    

    // 用于记录中序线索化上一个元素
    private HeroNode centerPre;

    public void threadedCenter(HeroNode node) 
        // 如果 node == null 就退出递归
        if (node == null) 
            return;
        

        // 线索化左子树
        threadedCenter(node.leftNode);


        // 处理左子树 如果 leftNode == null 就认为他是前驱结点
        if (node.leftNode == null) 
            // 设置为前驱节点
            node.leftNode = centerPre;
            // 设置为前驱类型
            node.leftType = 1;
        

        // 处理右子树 如果rightNode == null 就认为他是后继结点
        if (centerPre != null && centerPre.rightNode == null) 
            centerPre.rightNode = node;
            // 设置为后继结点类型
            centerPre.rightType = 1;
        

        // pre后移
        centerPre = node;

        // 线索化右子树
        threadedCenter(node.rightNode);
    

中序线索化遍历

public void showThreadedCenter(HeroNode node) 
        if (node == null) 
            return;
        

        // 如果是左子结点就遍历
        if (node.leftType == 0) 
            showThreadedPre(node.leftNode);
        
  
        System.out.println(node);

        // 如果是右子结点就遍历
        if (node.rightType == 0) 
            showThreadedPre(node.rightNode);
        
    

中序线索化和普通树结构遍历是类似的,只需要判断是否是左子 / 右子结点即可!

前序

前序遍历解决前解决后

可以看到前序遍历,如果前序线索化后,只浪费了一个结点 !

前序线索化

# ThreadedBinaryTree.java
  
// 记录前序线索化上一个元素
public HeroNode prePre;

public void threadedPre(HeroNode node) 
    // 如果node == null 就退出递归
    if (node == null) 
        return;
    

    // 和中序思路一样
    if (node.leftNode == null) 
        node.leftNode = prePre;
        node.leftType = 1;
    
    if (prePre != null && prePre.rightNode == null) 
        prePre.rightNode = node;
        prePre.rightType = 1;
    

    prePre = node;

    // 如果是左子结点点就去线索化 是前序结点就不走
    if (node.leftType == 0) 
        // 线索化左子树
        threadedPre(node.leftNode);
    

    // 如果是右子结点就去线索化 是后继结点就不走
    if (node.rightType == 0) 
        // 线索化右子树
        threadedPre(node.rightNode);
    

// endregion

这里思路和中序线索化一样,就不过多赘述了,来看看遍历吧

前序线索化遍历

# ThreadedBinaryTree.java
  
// region TODO 前序线索化遍历
// @author: android 超级兵
// @create: 2022/6/8 09:55
//
public void showThreadedPre() 
  showThreadedPre(root);

public void showThreadedPre(HeroNode root) 
    if (root == null) 
        return;
    
    System.out.println(root);
    if (root.leftType == 0) 
        showThreadedPre(root.leftNode);
    

    if (root.rightType == 0) 
        showThreadedPre(root.rightNode);
    

后续

后续遍历线索前线索后

代码思路和前序一样:直接看

后续线索化

# ThreadedBinaryTree.java
  
/*
 * 作者:android 超级兵
 * 创建时间: 6/7/22 5:48 PM
 */
private HeroNode lastPre;

public void threadedLast() 
    threadedLast(root);


public void threadedLast(HeroNode node) 
    if (node == null) 
        return;
    

    // 如果是左子结点才遍历
    if (node.leftType == 0) 
        // 线索化左子树
        threadedLast(node.leftNode);
    

    // 如果是右子结点才遍历
    if (node.rightType == 0) 
        // 线索化右子树
        threadedLast(node.rightNode);
    

    if (node.leftNode == null) 
        node.leftNode = lastPre;
        node.leftType = 1;
    

    if (lastPre != null && lastPre.rightNode == null) 
        lastPre.rightNode = node;
        lastPre.rightType = 1;
    

    lastPre = node;

//endregion

后续线索化遍历

# ThreadedBinaryTree.java
  
public void showThreadedLast() 
    showThreadedLast(root);


public void showThreadedLast(HeroNode root) 
		// 左子结点就遍历
    if (root.leftType == 0) 
        showThreadedLast(root.leftNode);
    

  	// 右子结点就遍历
    if (root.rightType == 0) 
        showThreadedLast(root.rightNode);
    

    System.out.println(root);

完整代码

原创不易,您的点赞就是对我最大的支持!

其他树结构文章:

  1. 二叉树入门
  2. 顺序二叉树
  3. 线索化二叉树 本篇
  4. 堆排序
  5. 赫夫曼树(一)
  6. 赫夫曼树(二)
  7. 赫夫曼树(三)
  8. 二叉排序树(BST)
  9. 平衡二叉排序树AVL
  10. 2-3树,2-3-4树,B树 B+树 B*树 了解
  11. 数据结构与算法:树 红黑树 (十一)

以上是关于数据结构与算法:树 线索化二叉树(中,前,后序)的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法__07--前序中序后序线索化二叉树,前序中序后序线索化二叉树遍历(Java语言版本)

超强二叉树解析.必收藏!(数组,链表实现,8种遍历方法,前,中,后序线索化二叉树及其遍历)---风之java

算法系列之线索化二叉树,前序线索化中序线索化后序线索化以及遍历~

学习数据结构笔记 --- [二叉树学习(BinaryTree)]

线索化二叉树

遍历及线索化二叉树