C语言线索二叉树基础解读
作者:洛语言 发布时间:2023-03-31 12:04:55
线索二叉树的意义
对于一个有n个节点的二叉树,每个节点有指向左右孩子的指针域。其中会出现n+ 1个空指针域,这些空间不储存任何事物,浪费着内存的资源。
对于一些需要频繁进行二叉树遍历操作的场合,二叉树的非递归遍历操作过程相对比较复杂,递归遍历虽然简单明了,但是会有额外的开销,对于操作的时间和空间都比较浪费。
我们可以考虑利用这些空地址,存放指向节点在某种遍历次序下的前驱和后继节点的地址。通过这些前驱和后继节点的地址可以知道,从当前位置下一步应该走向哪里。
线索二叉树的定义
指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树。
对二叉树以某种次序遍历使其变为线索二叉树的过程称为线索化。
线索二叉树结构的实现
二叉树的线索存储结构
为了区分二叉树某一节点是指向它的孩子节点还是指向前驱或者后继节点,我们可以在每个节点增设两个标志,Ltag,Rtag.
其中:
Ltag为0时,代表该节点指向它的左孩子,Ltag为1时,代表该节点指向它的前驱节点。
Rtag为0时,代表该节点指向它的右孩子,Rtag为1时,代表该节点指向它的后继节点。
所以,线索二叉树结构定义代码如下:
typedef char BTDataType;
typedef enum{Link,Thread}PointerTag;//Link 是0,Thread 是1。
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
PointerTag LTag ;
PointerTag RTag;
BTDataType data;
}BTNode;
二叉树的中序线索化
线索化的过程就是在遍历过程中修改空指针的过程
以上二叉树中序遍历可以得到:
D B E A F C
D的前驱是空,后继是B
B的前驱是D,后继是E
E的前驱是B,后继是A
F的前驱是A,后继是C
C的前驱是F,后继是空
线索化后:
中序遍历线索化的递归函数代码如下:
//中序线索化
BTNode* pre = NULL;/*全局变量,始终指向刚刚访问过的节点*/
void InThreading(BTNode* p)
{
if (p == NULL) return;
InThreading(p->left);//递归左子树线索化
if (!p->left)//左孩子为空,left指针指向前驱
{
p->LTag = Thread;
p->left = pre;
}
if (pre!=NULL && !pre->right)//右孩子为空,right指针指向后继指针。
//这里判断 pre!=NULL 是因为线索化中序遍历的第一个节点(节点D)时,它并没有前驱节点,此时的pre仍然是NULL。
{
pre->RTag = Thread;
pre->right = p;
}
pre = p;//保持pre指向p的前驱
InThreading(p->right);
}
分析:
if (!p->left)表示如果某节点的左指针域为空,因为其前驱节点刚刚访问过,并且赋值给了pre,所以可以将pre赋值给 l -> left,并且修改 p-> LTag = Thread,以完成前驱节点的线索化。
pre 是 p 的前驱,那么, p 就是 pre 的后继。当pre -> right 为空时,就可以将p赋值给 pre -> right , 并且修改 pre -> RTag = Thread。
线索二叉树的中序遍历
void MidOrder(BTNode*p)
{
while (p != NULL)
{
while (p->LTag == Link)//
{
p = p->left;
}
printf("%c ",p->data);
while (p->RTag == Thread && p->right != p)
{
p = p->right;
printf("%c ", p->data);
}
p = p->right;
}
return;
}
分析:
while (T->ltag == Link)从根节点开始遍历,如果左标记是Link让它一直循环下去,直到找到标记为Thread的的结点,也就是要遍历的第一个结点,然后根据后驱指针找到后继结点
后面就是重复以上过程,直到遍历完整个二叉数。
来源:https://blog.csdn.net/m0_62969222/article/details/124212207


猜你喜欢
- 背景系统: SpringBoot开发的Web应用;ORM: JPA(Hibernate)接口功能简述: 根据实体类ID到数据库中查询实体信息
- 最近一直在对接接口,上游返回的都是 JSON 数据,我们需要将这些数据进行保存,我们可以解析成 Map 通过 key 的方式进行获取,然后
- 1、使用JPA 的@Enumerated 注解 ,可以直接将Enum映射到数据库中。但是value的值只有两种方式选择,一种是使用枚举的序号
- 本文实例为大家分享了Java手写线程池的实现代码,供大家参考,具体内容如下1.线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在
- 本文实例讲述了C#实现顺序表(线性表)的方法。分享给大家供大家参考,具体如下:基本思想是使用数组作为盛放元素的容器,数组一开始的大小要实现确
- 前言上一篇已经对线程池的创建进行了分析,了解线程池既有预设的模板,也提供多种参数支撑灵活的定制。本文将会围绕线程池的生命周期,分析线程池执行
- 来源:https://www.cnblogs.com/fanweisheng/p/11440
- 仅做学习交流,如有侵犯联系必删。前言一篇酷狗app安卓逆向的文章,难度适中。样本: 酷狗app v10.8.8工具: jadx、Pixel3
- 一、什么是Java事务通常的观念认为,事务仅与数据库相关。  
- 最近在搭建springmvc的框架,遇到的这样的问题:在地址栏访问登陆界面访问不了,http://localhost/XXXX/WEB-IN
- 前言在一些项目中,经常会遇到需要把当前线程中的上下文传递到其他线程中的情况,比如某项目包含国际化操作,在业务请求进来时需要把对应的国家代码存
- 一、logback日志技术介绍Spring Boot中使用的日志技术为logback。其与Log4J都出自同一人,性能要优于Log4J,是L
- C#删除指定文件或文件夹public static string deleteOneFile(string fileFullPath) &n
- 上一篇:瑞吉外卖项目:新增员工一. 员工信息分页查询1. 需求分析当系统中的用户越来越多页面展示不完整,我们需要通过实现分页的方式去展示员工
- 首先,想要明白hashCode的作用,你必须要先知道Java中的集合。 总的来说,Java中的集合(Collection)有两类,一类是Li
- 概述不知道大家在各自项目中是如何写提供代码的commit message, 我们项目有的同事写的很简单,压根不知道提交了什么内容,是新功能还
- 最近上线的项目中数据库数据已经临近饱和,最大的一张表数据已经接近3000W,百万数据的表也有几张,项目要求读数据(select)时间不能超过
- 项目需要用到验证用户手机号码输入是否合法,在网上找了好几处代码,经过测试都是不通过的!最后发现了一段代码可以验证通过。代码好像在一个很多广告
- 要实现PPT转图片,首先需要引用两个DLL。我这里用的这个这个版本Microsoft.Office.Interop.PowerPoint 1
- 初步探索首先我们要了解equals方法是什么,hashcode方法是什么。equals方法equals 是java的obejct类的一个方法