【数据结构】10.线索二叉树

ops/2024/11/17 8:20:10/

一、线索二叉树的产生

采用先序、中序、后序三种方法遍历二叉树后都可以得到一个线性序列,序列上的每一个结点(除了第一个和最后一个)都有一个前驱和一个后继,但是,这个线性序列只是逻辑的概念,不是物理结构。
在这里插入图片描述
二叉链体现的是父子关系,不一定是结点在遍历序列中的前驱和后继。

在有n个结点的二叉链表中,有n+1个空指针 。那么能否利用这些空指针来存放前驱和后继结点的地址呢?然后可以像遍历链表一样方便的遍历二叉树序列呢?
这也就是线索二叉树产生的背景。线索二叉树可以解决部分的上述问题,加快在序列中查找前驱和后继节点的速度,但同样的也增加了在树中插入和删除节点的难度。

二、二叉树线索化

二叉树线索化是将二叉链表中的空指针改为指向前驱或后继结点。而前驱结点和后继结点只要在遍历时才能拿到,所有二叉树线索化分为先序线索二叉树、中序线索二叉树和后序线索二叉树

如果当前节点没有左子树,那么该节点的左指针指向遍历序列中它的前驱结点。
如果当前节点没有右子树,那么该节点的右指针指向遍历序列中它的后继结点。

在这里插入图片描述

2.1 线索二叉树的定义

typedef int ThreadedBinaryTreeDataType;typedef struct ThreadedBinaryTree
{ThreadedBinaryTreeDataType _data;	struct ThreadedBinaryTree* _left;	struct ThreadedBinaryTree* _right;int _LeftFlag, _RightFlag;	//左右指针类型:0表示非线索指针,1表示线索指针
}TBT,*pTBT;

2.2 先序线索二叉树

在这里插入图片描述
将二叉树进行先序遍历得到的序列就是先序序列,我们需要将他们进行连接。很显然,我们需要找到每一个结点的后继结点。

如果当前结点的右指针存放的是线索,右指针指向的结点即为后续节点。
如果当前结点的右指针存放的是结点,取左子结点,如果左子结点为空,取右子结点。

void _ThreadedPrevOrder(TBT* root)
{if (root == NULL)return;if (root->left == NULL){root->left = prev;root->LeftFlag = 1;}if (prev && prev->right == NULL){prev->right = root;prev->RightFlag = 1;}prev = root;if(root->LeftFlag==0)_ThreadedPrevOrder(root->left);if(root->RightFlag==0)_ThreadedPrevOrder(root->right);
}void ThreadedPrevOrder(TBT* root)
{if (root == NULL)return;_ThreadedPrevOrder(root);prev->right = NULL;prev->RightFlag = 1;
}

2.3 后序线索二叉树

在这里插入图片描述
同样的,将二叉树进行后序遍历得到的序列就是后序序列,我们需要将他们进行连接。很显然,我们需要找到每一个结点的前驱结点。

如果当前结点的左指针存放的是线索,左指针指向的结点即为前驱节点。
如果当前结点的左指针存放的是结点,取右子结点,如果右子结点为空,取左子结点。

void _ThreadedPostOrder(TBT* root)
{if (root == NULL)return;_ThreadedPostOrder(root->left);_ThreadedPostOrder(root->right);if (root->left == NULL){root->left = prev;root->LeftFlag = 1;}if (prev && prev->right == NULL){prev->right = root;prev->RightFlag = 1;}prev = root;
}void ThreadedPostOrder(TBT* root)
{if (root == NULL)return;_ThreadedPostOrder(root);
}

2.4 中序线索二叉树

在这里插入图片描述
将二叉树进行中序遍历得到的序列就是中序序列,我们需要将他们进行连接。很显然,我们需要找到每一个结点的前驱结点和后续结点。

如果当前结点的右指针存放的是线索,右指针指向的结点即为后续节点。
如果当前结点的右指针存放的是结点,右子树中序遍历序列的第一个结点(最左)就是后续节点。
如果当前结点的左指针存放的是线索,左指针指向的结点即为前驱节点。
如果当前结点的左指针存放的是结点,左子树中序遍历序列的最后一个结点(最右)就是后续节点。

void _ThreadedInOrder(TBT* root)
{if (root == NULL)return;_ThreadedInOrder(root->left);if (root->left == NULL){root->left = prev;root->LeftFlag = 1;}if (prev && prev->right == NULL){prev->right = root;prev->RightFlag = 1;}prev = root;_ThreadedInOrder(root->right);
}void ThreadedInOrder(TBT* root)
{if (root == NULL)return;_ThreadedInOrder(root);prev->right = NULL;prev->RightFlag = 1;
}

三、遍历线索二叉树

3.1 遍历中序线索二叉树

void inOrderTraverseThTree(TBT* root)
{//找到初始节点TBT* head = root;while (head->left)head = head->left;while (head){printf("%d ", head->data);//找下一个访问的结点if (head->right && head->RightFlag == 1)head = head->right;else if (head->right){head = head->right;while (head->left && head->LeftFlag == 0)head = head->left;}else if (head->right == NULL)break;}
}

3.2 遍历先序线索二叉树

void PrevOrderTraverseThTree(TBT* root)
{TBT* head = root;while (head){printf("%d ", head->data);if (head->LeftFlag == 0)head = head->left;elsehead = head->right;}
}

3.3 遍历后序线索二叉树

对于后序线索二叉树的遍历是要复杂一点的,对于根节点的后继结点是不好定位的,最好使用到三叉链,当然也可以迭代找到,这里就不演示了


http://www.ppmy.cn/ops/134372.html

相关文章

MySQL的编程语言

一、MySQL基础 使用系统的全局变量@@VERSION查看当前使用的MySQL的版本信息,SQL语句如下: select @@version; 将局部变量varl声明为char的类型,长度值为10,并为其赋值为“程菲” begin declare var1 char(10); set @var1="程菲"; end 通过局部变量查看d_eams数…

Flink_DataStreamAPI_源算子Source

Flink_DataStreamAPI_源算子Source 1从集合中读取数据2从文件读取数据3从Socket读取数据4从Kafka读取数据5从数据生成器读取数据Flink支持的数据类型1)Flink的类型系统2)Flink支持的数据类型3)类型提示(Type Hints) 1从…

springboot整合security5.7.16实现用户登录及超时自动登录

1、问题概述? 提供源码下载,springSecurity关键技术,仔细阅读。 解决如下问题: 1、使用springboot2.7.16整合springSecurity5.7.16实现用户登录 2、解决新版本的Security的配置文件-提供完整配置。 3、当用户登录信息失效后,在界面发送的ajax,如何重定向到login.htm…

Android Framework与JNI

本文以 android-12.0.0_r34 的代码进行分析。 framework中的JNI 通常来说,Android framework 中使用到的 native 函数都是动态注册的,而且注册过程有固定的套路。我们以Parcel类为例来解析套路。 首先,我们在Parcel.java中会看到很多标记为…

Java-02 深入浅出 MyBatis - MyBatis 快速入门(无 Spring) POM Mapper 核心文件 增删改查

点一下关注吧!!!非常感谢!!持续更新!!! 大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了: MyBatis&#xff…

freemarker 读取template.xml ,通过response 输出文件,解决中文乱码问题

采用 try (Writer writer new OutputStreamWriter(os, “UTF-8”)) UTF-8 内容转换 public static void setResponseHeader(HttpServletResponse response, String fileName) {try {// fileName "中文.xls";try {fileName new String(fileName.getBytes(),"…

PostgreSQL中的COPY命令:高效数据导入与导出

在PostgreSQL数据库中,数据导入和导出是日常工作中常见的操作。传统的插入(INSERT)方法虽然可以实现数据的导入,但在处理大量数据时效率较低。而COPY命令则提供了一个快速、高效的方式来完成这一任务。COPY命令不仅可以用于将数据…

在启动 Spring Boot 项目时,报找不到 slf4j 的错误

而且 tomcat 的启动信息不知道为什么输出出来了 问 AI 得到的解决方案&#xff1a; 将 pom.xml 中的如下配置替换成这样&#xff0c;排除这个插件 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring - boot - starter - …