线索二叉树详解 - C语言

2023-11-09

目录

一、线索二叉树的定义

1.1 线索的概念

1.2 数据结构

1.3 优缺点

二、线索二叉树的构建

2.1 线索化

2.2 实现中序遍历线索化

三、线索二叉树的应用

3.1 求某个结点的中序后继

3.2 使用前驱后继遍历线索二叉树


对于二叉树,有以下几个问题:

1. 二叉链表的空间利用情况如何?

        答:在n个结点的二叉树左右链表示中,只有n-1个指向子树的指针,却有n+1个空指针域。是否有些浪费?

2. 二叉链表中如何找某个结点的某种遍历的前驱和后驱?

        答:每次都要从根节点开始遍历。是否有些麻烦?

3. 如何遍历二叉链表表示的二叉树

        答:利用栈或队列。可不可以不用呢?

为了解决上述问题,线索二叉树应运而生。


一、线索二叉树的定义

1.1 线索的概念

对于n个结点的二叉树,在二叉链存储结构中有n+1个空链域,利用这些空链域存放在某种遍历次序下该结点的前驱结点和后继结点的指针,这些指针称为线索,加上线索的二叉树称为线索二叉树(Threaded BinaryTree)

1.2 数据结构

其数据结构定义如下:

/* 线索二叉树结构 */
struct Node
{
    char data;
    struct Node *lchild, *rchild;
    int ltag, rtag;
};

其中,

可以看到,child位置被充分利用起来,利用了所有的空指针;tag用以区分该结点的两个指针域指向左右孩子还是前驱后驱。

1.3 优缺点

那么这么做有什么好处呢?

优点:

① 利用线索二叉树进行某种遍历时,不必采用堆栈处理,速度较一般二叉树的遍历速度快,且节约存储空间。

② 任意一个结点都能直接找到它的前驱和后继结点。

缺点:

① 结点的插入和删除麻烦,且速度也较慢。

② 线索子树不能共用。


二、线索二叉树的构建

2.1 线索化

将结点的空指针域指向其前驱/后继的指针被称为线索;结点的空链域存放其前驱后继的过程称为线索化

显然,二叉树的遍历方式有4种,故对应了4种线索二叉树:

(1)先序线索二叉树;

(2)中序线索二叉树;

(3)后序线索二叉树;

(4)层序线索二叉树。

2.2 实现中序遍历线索化

如何将一个二叉树线索化?一言以蔽之:正常遍历的过程中将前后驱存起来即可。因此其框架与遍历相同,只需修改”访问结点“部分。以中序遍历为例,其线索化的操作具体为:

记录前驱:如果该结点没有左孩子,则把其ltag置为1,并把其lchild置为前驱pre;

记录后驱:后驱并不和前驱一样,因为在遍历至当前结点时,并不知道该结点的后驱是谁,所以我们并不能简单地将判断设置为”如果该结点的右孩子为空“,而是要将当前结点的记录后驱部分留给要遍历的下一个结点来做。

因此我们采取以下判断策略:如果当前结点的前驱不为空(说明不是首结点),并且前驱的右孩子为空(说明前驱需要记录后继,而此刻遍历到的结点正是前驱的后继),便将前驱的rchild记为当前结点,同时把其rtag置为1。记录后驱,并不是说把当前结点的后驱记录下来,而是给上一个结点”擦屁股“,把上一个结点的后驱给补上;

③ 最后将前驱更新为当前结点。

这里给出一棵树,以便读者结合图像来理解。

其中序遍历为: G D I H B A E J C F

代码示例:

 ThTree pre = NULL;  // 全局变量,记录前驱
 ​
 /* 中序线索二叉树线索化 */
 void inOrderThTree(ThTree BT)
 {
     if (BT)
     {
         inOrderThTree(BT->lchild); // 遍历左子树
 ​
         // 线索化
         if (!BT->lchild) // 没有左孩子时
         {
             BT->ltag = 1;     // 标记tag
             BT->lchild = pre; // 前驱
         }
         if (pre && !pre->rchild)  // 前驱不为空且前驱的右孩子为空
         {
             pre->rchild = BT;
             pre->rtag = 1;
         }
         pre = BT;  // 更新前驱为当前节点
          
         inOrderThTree(BT->rchild); // 遍历右子树
     }
 }

关于其余3种线索树,请读者自行实现。

三、线索二叉树的应用

以下仍以上述构建的中序线索二叉树为例。

3.1 求某个结点的中序后继

思路:

① 当结点(记为p)的rtag为1时,其后续(记为post)即为p->rchild;

② 当p->rtag == 0时,post为p的右子树的最左结点。

代码示例:

 /* 求中序线索树结点的后继 */
 ThTree inNext(ThTree p)
 {
     ThTree post = NULL; // 后继结点
     if (p->rtag)        // 如果有后继,直接返回
         return p->rchild;
     else // 如果有右孩子,则后继在右子树的最左结点
     {
         if(!p->rchild) return NULL;
         post = p->rchild;
         if (post->rtag == 0 && post->rchild == NULL)
             return post;
         while (post->ltag == 0 && post->lchild != NULL) // 往左走到头
         {
             post = post->lchild;
         }
         return post;
     }
 }

3.2 使用前驱后继遍历线索二叉树

当结点中保存了前驱和后继的信息之后,便不需要再反复递归调用来遍历二叉树。

代码示例:

 /* 前驱后继中序遍历线索二叉树 */
 void inOrderTraverseThTree(ThTree BT)
 {
     ThTree head = BT;
     while (head->lchild && head->ltag == 0)  // 找到起点
         head = head->lchild;
     while (head != NULL)
     {
         if (head)
             printf("%c ", head->data);
         head = inNext(head);
     }
 }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线索二叉树详解 - C语言 的相关文章

随机推荐

  • css文字垂直居中

    div class style text align center margin top 20px div class style background F9C356 width 80 height 70px margin 0 auto d
  • 子网掩码是什么,IP段的24是什么写法(CIDR写法,斜杠记法斜线记法)

    背景 关于设置 IP 网段 我们常见到的 192 168 1 0 24 是什么意思 24是什么意思 这里的 192 168 1 0 的末尾0是 一定是0吗 跟 192 168 1 5 24 所表示的网段是一样的吗 补充 其实 24类似这种写
  • STM32F103ZET6-ESP8266驱动程序

    ESP8266 WIFI 模块如下图所示 WIFI 模块尺寸图如下图所示 如果需要将此模块设计到自己产品内 可能需要参考这个尺寸值 WIFI模块插在开发板上 如下图所示 从 WIFI 模块实物图中可以看到 WIFI 模块提供了一个 2 4
  • K Nearest Neighbor 算法

    2019独角兽企业重金招聘Python工程师标准 gt gt gt K Nearest Neighbor算法又叫KNN算法 这个算法是机器学习里面一个比较经典的算法 总体来说KNN算法是相对比较容易理解的算法 其中的K表示最接近自己的K个数
  • Black Screen Remote Desktop to Ubuntu from Windows with XRDP

    We have noticed that a lot of people hit the same issue over and over again When trying to connect via remote desktop pr
  • 相机标定-基础(一)

    1 何为相机标定 当相机拍摄照片时 我们看到的图像通常与我们实际看到的不完全相同 这是由相机镜头引起的 而且发生的频率比我们想象的要高 这种图像的改变就是我们所说的畸变 一般来说 畸变是指直线在图像中出现弯曲或弯曲 这种畸变我们可以通过相机
  • Python网络编程

    本地的进程间通信 IPC 有很多种方式 但可以总结为下面4类 消息传递 管道 FIFO 消息队列 同步 互斥量 条件变量 读写锁 文件和写记录锁 信号量 共享内存 匿名的和具名的 远程过程调用 Solaris门和Sun RPC 网络中进程之
  • pytest右键显示run pytest for XX.py

    进入 File settings python integrated tools里面修改 选择unittest
  • C++相关容器篇章

    内容 链接 vector 点击链接 stack和queue的函数用法 点击链接 优先队列priority queue
  • IDEA打包失败(多个module之间依赖不能识别)

    背景 开发过程中总会遇到一些不那么合理的架构 一个服务多个module 前后端不分离 于是需要自己打镜像 然后发到docker hub 再起服务 于是就有了第一步 本地打包的过程 idea提供了很方便的打包功能 然后出现异常 异常原因 we
  • 不限次数的chatGPT

    不说废话直接看方法 不用翻墙 开干 第一步 打开电脑的Edge浏览器 就是windows系统的默认浏览器 搜索wetab 点击如下的官方链接就会进入安装插件界面 第二步 点击chat AI就会弹出这个弹窗 点击 安装教程 按钮 第三步 来到
  • 企业微信跳转体验版小程序

    企业微信的 菜单中的H5页面要通过分享卡片跳转到小程序 测试时发现只能跳转正式环境 且 分享消息到当前会话 接口没有提供跳转体验版的参数 技术人想办法 要做多方案准备 终于可以了 企业微信提供了 小程序 打开多场景调试 这样打开了体验版开关
  • 温昱书评:读《代码之道》

    索然无味 毫无观点的书永远引不起人们的阅读兴趣 放心 代码之道 绝对不是 形式上 本书中的每一篇文章都通过讲故事等方式提出问题 然后分析问题根源 最后给出改善建议 其中 问题的提出往往极具戏剧效果 作者也坦承 为了达到效果 我又一次夸大了问
  • CUDA的cublas 和 Intel的MKL 矩阵运算对比

    CUBLAS和MKL都是快速矩阵运算的工具 一个适用Intel的cpu 一个适用于nvidia的GPU 最近在做RNN 循环神经网络 的加速 其中一点就是把神经网络的矩阵运算放到CPU上算 所以就做了一点相关的测试 以前我们实验室的RNN用
  • Java文件读写和CSV文件解析(读取csv文件的一列或若干列)

    文件类 Java 读文件流的知识不可少 先复习一下吧 OREACLE JDK8 DOCS 文件类是Java IO的一个对象 用于指定文件的相关信息 位置和名称信息 如txt文件 csv文件对Java来说就是一个文件类 开发手册中指出 文件类
  • agv小车-qt-ros控制注说明

    转过来 控制 地图 看上去也是json mqtt 通迅是一样的 单片机端添加ros json接口 由上位机获取单片机控制端的三轴 gps 姿态 轨迹数据后由json更新控制参数实现在agv小车在地图上面的动作控制 1 ui接口类与ros连接
  • 输入n位评委,并输入评委的打分,去掉最高最低分求均值

    Test public void average double ave 0 double sum 0 double min 0 double max 0 往数组输入数值 Scanner InputPepole new Scanner Sys
  • 学计算机用苹果本,如何快速学会使用苹果电脑?

    我过去很多年一直使用Windows系统 前几年由于买了苹果手机iPhone以及使用了iPad 对苹果系统有了一些好感 于是在前年决定买一台苹果电脑 就这样我开始使用苹果电脑 我发现 苹果电脑与Windows系统还是有很多不同 所以一开始并不
  • 区块链加密算法总结

    文章目录 1 对称加密 DES Data EncryptionStandard 3DES Triple DES AES Advanced EncryptionStandard 2 非对称加密 RSA加密法 DSA Digital Signa
  • 线索二叉树详解 - C语言

    目录 一 线索二叉树的定义 1 1 线索的概念 1 2 数据结构 1 3 优缺点 二 线索二叉树的构建 2 1 线索化 2 2 实现中序遍历线索化 三 线索二叉树的应用 3 1 求某个结点的中序后继 3 2 使用前驱后继遍历线索二叉树 对于