二叉树的遍历和线索二叉树--中序线索二叉树的构造

一、为什么要用线索二叉树

普通二叉链表:

  • n 个结点,一共2n 个指针域

  • 真正指向孩子的指针只有 n-1 个

  • 剩余 n+1 个空指针,空间浪费

解决办法:

利用空左、空右指针,存放中序遍历的前驱、后继结点

加上标记位区分,就是中序线索二叉树


二、线索结点结构

复制代码
数据 data
左指针 lchild  + 左标记 ltag
右指针 rchild  + 右标记 rtag
  • `ltag = 0`:lchild 指向左孩子

  • `ltag = 1`:lchild 是前驱线索

  • `rtag = 0`:rchild 指向右孩子

  • `rtag = 1`:rchild 是后继线索


三、构造核心规则(中序:左→根→右)

  1. 按照中序遍历顺序递归遍历整棵树

  2. 定义全局指针 `pre`,永远记录上一个访问过的结点

  3. 当前结点左孩子为空

→ 左指针指向 `pre`,`ltag=1`

  1. 前驱结点 `pre` 右孩子为空

→ pre 右指针指向当前结点,`pre.rtag=1`

  1. 遍历完当前结点,更新 `pre = 当前结点`

四、一步步构造流程(画图逻辑)

  1. 初始化 `pre = null`

  2. 递归线索化左子树

  3. 处理当前根结点:绑定前驱线索

  4. 绑定前驱结点到当前结点的后继线索

  5. 更新前驱 pre

  6. 递归线索化右子树


五、Java 标准构造代码

1.线索结点类

复制代码
class InThreadNode {
    int data;
    InThreadNode left;
    InThreadNode right;
    int ltag;   //0=左孩子  1=前驱线索
    int rtag;   //0=右孩子  1=后继线索

    public InThreadNode(int data) {
        this.data = data;
        left = null;
        right = null;
        ltag = 0;
        rtag = 0;
    }
}

2.中序线索化核心递归代码

复制代码
public class ThreadTree {
    static InThreadNode pre = null; //记录前驱结点

    //中序遍历实现二叉树线索化
    public void createInThread(InThreadNode root) {
        if (root == null) return;

        //1.递归线索化左子树
        createInThread(root.left);

        //2.处理当前结点:左空 → 指向前驱
        if (root.left == null) {
            root.left = pre;
            root.ltag = 1;
        }

        //3.处理前驱结点:右空 → 指向当前结点(后继)
        if (pre != null && pre.right == null) {
            pre.right = root;
            pre.rtag = 1;
        }

        //前驱后移
        pre = root;

        //4.递归线索化右子树
        createInThread(root.right);
    }
}

六、中序线索二叉树遍历(不用栈、不用递归)

复制代码
//线索树遍历
public void threadTraverse(InThreadNode root){
    InThreadNode p = root;

    //找到中序第一个结点(最左下)
    while(p != null && p.ltag == 0){
        p = p.left;
    }

    while(p != null){
        System.out.print(p.data + " ");

        //右是线索,直接走后继
        if(p.rtag == 1){
            p = p.right;
        }
        //右是孩子,找右子树最左下结点
        else{
            p = p.right;
            while(p != null && p.ltag == 0){
                p = p.left;
            }
        }
    }
}

七、考点

  1. 线索化本质 = 一次完整中序遍历

  2. `pre` 是连接前驱后继的关键

  3. 叶子结点:左右指针全部是线索

  4. 线索二叉树:无需递归、无需栈即可遍历

  5. n 个结点二叉链表,固定空指针数量:n+1 个

  6. 中序线索树找前驱后继最简单,先序、后序很复杂


八、优缺点

优点

  • 充分利用空闲指针,不额外占用空间

  • 非递归快速遍历

  • 快速查询结点遍历前驱、后继

缺点

  • 插入、删除结点麻烦,需要重新修改所有线索

  • 树结构改动代价大

相关推荐
Logic1019 小时前
C语言/数据结构位运算题解:异或XOR找出蛋糕订单中的“VIP独特口味“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
Logic10110 小时前
C语言/数据结构位运算题解:异或XOR找出飞行棋中的“独特颜色棋子“——只出现一次的数字
c语言·数据结构·数组·位运算·时间复杂度·算法题·异或性质
爱吃苹果的日记本10 小时前
数据结构第三课(时间复杂度)
数据结构·学习
Logic10112 小时前
C语言/数据动态规划题解:翻转一次子数组后的最大子数组和——四状态DP(O(n)时间O(1)空间)
c语言·数据结构·动态规划·时间复杂度·算法题·状态机dp·最大子数组和
小π军13 小时前
最大重叠区间数量
数据结构·算法
Logic10113 小时前
C语言/数据结构字符串题解:找出DNA序列中未配对的独特序列——排序+遍历(O(nlogn))
c语言·数据结构·字符串·数组·排序·时间复杂度·算法题
wzdark14 小时前
基于链表的内存池设计与内存复用机制4
java·数据结构·链表
BizzZ_17 小时前
算法(1)——双指针
数据结构
Doubbbbbbble云17 小时前
内存碎片化对数据结构操作性能的影响研究4
数据结构
xiangyun6119 小时前
【408数据结构 03】线性表与顺序表:C++手写SeqList
开发语言·数据结构·c++