线索二叉树是一种对普通二叉树进行扩展的数据结构,旨在提高遍历效率

线索二叉树是一种对普通二叉树进行扩展的数据结构,旨在提高遍历效率。其核心思想是利用二叉链表中大量的空指针域来保存节点在某种遍历顺序下的前驱和后继信息。

  1. 定义
    线索二叉树(Threaded Binary Tree)是在二叉树的基础上,通过修改空指针使其指向该节点在某种遍历序列(如先序、中序或后序)中的前驱或后继节点,从而形成的特殊二叉树。这种被“线索化”的结构使得不使用递归或栈也能高效地进行遍历操作。

  2. 存储结构
    每个节点包含五个部分:

    • ltag:左标志位,0 表示 lchild 指向左孩子,1 表示 lchild 指向前驱;
    • lchild:左指针;
    • data:数据域;
    • rchild:右指针;
    • rtag:右标志位,0 表示 rchild 指向右孩子,1 表示 rchild 指向后继。

    结构示例如下(以中序线索二叉树为例):

        A
       / \
      B   C
     / \
    D   E
    

    中序遍历为:D → B → E → A → C
    线索化后,D 的 rchild(原为空)将指向 B(后继),B 的 lchild(若为空)将指向前驱 D,以此类推。

  3. 线索化过程
    在进行中序遍历时,设置一个全局指针 pre 初始为 null,当访问当前节点 p 时:

    • pre != nullpre 的右指针为空,则将其 rtag 设为 1,并让 rchild 指向 p(即 pre 的后继是 p);
    • p 的左指针为空,则将其 ltag 设为 1,并让 lchild 指向 pre(即 p 的前驱是 pre);
    • 更新 pre = p,继续遍历。

    示例代码(中序线索化):

    typedef struct ThreadNode {
        char data;
        struct ThreadNode *lchild, *rchild;
        int ltag, rtag;  // 0: child, 1: thread
    } ThreadNode, *ThreadTree;
    
    ThreadNode *pre = NULL;  // 指向前一个访问的节点
    
    void inorderThreading(ThreadNode *p) {
        if (p == NULL) return;
        
        inorderThreading(p->lchild);  // 遍历左子树
    
        // 处理当前节点
        if (p->lchild == NULL) {
            p->ltag = 1;
            p->lchild = pre;
        }
        if (pre != NULL && pre->rchild == NULL) {
            pre->rtag = 1;
            pre->rchild = p;
        }
        pre = p;
    
        inorderThreading(p->rchild);  // 遍历右子树
    }
    
  4. 作用与优势

    • 提高遍历效率:无需栈或递归即可完成遍历;
    • 节省空间:利用原本浪费的空指针域存储有用信息;
    • 快速查找前驱/后继:在线索二叉树中可直接定位某节点的直接前驱或后继;
    • 适用于频繁遍历但结构稳定的二叉树场景。
      实现中序线索二叉树的非递归遍历,关键在于利用 ltagrtag 标志位判断指针是指向孩子还是线索(前驱/后继),从而避免使用栈或递归。

基本思路:

  1. 从根节点开始,找到中序序列的第一个节点(即最左下的节点);
  2. 遍历过程中:
    • 若当前节点的 rtag == 1,说明 rchild 指向的是中序后继,直接跳转;
    • rtag == 0,说明有右孩子,则进入右子树,并找到该子树中序遍历的第一个节点(即右子树中最左边的节点);
  3. 重复直到所有节点访问完毕。

C语言实现代码:

#include <stdio.h>

typedef struct ThreadNode {
    char data;
    struct ThreadNode *lchild, *rchild;
    int ltag, rtag;  // 0: child, 1: thread
} ThreadNode, *ThreadTree;

// 非递归中序遍历线索二叉树
void inorderTraverse(ThreadTree root) {
    ThreadNode *p = root;

    // 找到中序第一个节点:一直向左直到 ltag == 1
    while (p != NULL && p->ltag == 0) {
        p = p->lchild;
    }

    // 遍历整个线索二叉树
    while (p != NULL) {
        printf("%c ", p->data);  // 访问当前节点

        // 如果 rtag == 1,rchild 是后继线索,直接跳转
        if (p->rtag == 1) {
            p = p->rchild;
        }
        // 否则进入右子树,找右子树的最左节点
        else {
            p = p->rchild;
            while (p != NULL && p->ltag == 0) {
                p = p->lchild;
            }
        }
    }
}

示例说明:

假设有一棵中序线索化的二叉树如下:

    A
   / \
  B   C
 / \
D   E

中序遍历序列:D → B → E → A → C

线索化后:

  • D 的 rchild 指向 B(后继),rtag = 1
  • B 的 lchild 指向 D(前驱),ltag = 1
  • E 的 rchild 指向 A(后继),rtag = 1
  • A 的 lchild 指向 E(前驱),ltag = 1
  • C 的前后无更多节点,视情况处理

调用 inorderTraverse(root) 将输出:D B E A C


注意事项:

  • 必须确保线索化已完成,否则行为未定义;
  • 头节点可增设一个“头结点”统一管理起始与结束(如将最后一个节点的后继指向头结点,形成循环线索树);
  • 时间复杂度:O(n),每个节点访问一次;
  • 空间复杂度:O(1),无需额外栈空间。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Bol5261

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

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

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

打赏作者

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

抵扣说明:

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

余额充值