数据结构(5.3_5)——二叉树的线索化

第一种寻找中序前驱方法

 中序线索化

本质上就是一次中序遍历,只不过需要在一边遍历一边处理结点线索化

代码:


//全局变量pre 指向当前访问结点的前驱
ThreadNode* pre = NULL;struct ElemType {int value;
};//线索二叉树结点
typedef struct ThreadNode {ElemType data;struct ThreadNode* lchild, * rchild;int ltag, rtag;//左、右线索标志
} ThreadNode, * ThreadTree;
//中序遍历二叉树,一边遍历一边线索化
void InThread(ThreadTree T) {if (T != NULL) {InThread(T->lchild); // 递归遍历左子树visit(T); // 访问根节点InThread(T->rchild); // 递归遍历右子树}
}
void visit(ThreadNode* q) {if (q->lchild == NULL) { // 左子树为空,建立前驱线索q->lchild = pre;q->ltag = 1;}if (pre != NULL && pre->rchild == NULL) { // 建立前驱结点的后继线索pre->rchild = q;pre->rtag = 1;}pre = q; // 更新前驱为当前结点
}//中序线索化二叉树Tvoid CreatePreThread(ThreadTree T) {pre = NULL;//pre初始为空if (T != NULL) {//非空二叉树才能线索化InThread(T);//先序线索化二叉树if (pre->rchild == NULL)pre->rtag = 1;//处理遍历的最后一个结点}}

先序线索化

本质上就是一次先序遍历,只不过需要在一边遍历一边处理结点线索化

代码:

//全局变量pre 指向当前访问结点的前驱
ThreadNode* pre = NULL;struct ElemType {int value;
};//线索二叉树结点
typedef struct ThreadNode {ElemType data;struct ThreadNode* lchild, * rchild;int ltag, rtag;//左、右线索标志
} ThreadNode, * ThreadTree;
//先序遍历二叉树,一边遍历一边线索化
void PreThread(ThreadTree T) {if (T != NULL) {visit(T); // 访问根节点if(T->ltag==0)//lchild不是前驱线索PreThread(T->lchild); // 递归遍历左子树if (T->rtag==0)//rchild不是前驱线索PreThread(T->rchild); // 递归遍历右子树}
}
void visit(ThreadNode* q) {if (q->lchild == NULL) { // 左子树为空,建立前驱线索q->lchild = pre;q->ltag = 1;}if (pre != NULL && pre->rchild == NULL) { // 建立前驱结点的后继线索pre->rchild = q;pre->rtag = 1;}pre = q; // 更新前驱为当前结点
}
//先序线索化二叉树Tvoid CreatePreThread(ThreadTree T){pre = NULL;//pre初始为空if (T != NULL) {//非空二叉树才能线索化PreThread(T);//先序线索化二叉树if (pre->rchild == NULL)pre->rtag = 1;//处理遍历的最后一个结点}
}

注意:若在PreThread函数中不添加

 if(T->ltag==0)

可能会导致某一结点的pre指针陷入无限循环 

后序线索化

本质上就是一次后序遍历,只不过需要在一边遍历一边处理结点线索化

代码:


//全局变量pre 指向当前访问结点的前驱
ThreadNode* pre = NULL;struct ElemType {int value;
};//线索二叉树结点
typedef struct ThreadNode {ElemType data;struct ThreadNode* lchild, * rchild;int ltag, rtag;//左、右线索标志
} ThreadNode, * ThreadTree;
//后序遍历二叉树,一边遍历一边线索化
void PostThread(ThreadTree T) {if (T != NULL) {PostThread(T->lchild); // 递归遍历左子树PostThread(T->rchild); // 递归遍历右子树visit(T); // 访问根节点}
}
void visit(ThreadNode* q) {if (q->lchild == NULL) { // 左子树为空,建立前驱线索q->lchild = pre;q->ltag = 1;}if (pre != NULL && pre->rchild == NULL) { // 建立前驱结点的后继线索pre->rchild = q;pre->rtag = 1;}pre = q; // 更新前驱为当前结点
}
//后序线索化二叉树Tvoid CreatePreThread(ThreadTree T){pre = NULL;//pre初始为空if (T != NULL) {//非空二叉树才能线索化PostThread(T);//先序线索化二叉树if (pre->rchild == NULL)pre->rtag = 1;//处理遍历的最后一个结点}
}

为什么中序线索化和后序线索化不会遇到怕死循环问题 :

中序线索化:

  1. 线索化时机:在中序线索化过程中,一个节点的左线索是在其左子树遍历完成之后设置的,而右线索是在其右子树遍历完成之后设置的。这意味着在设置线索时,子树的遍历已经完成,因此不会覆盖未遍历的子节点指针。

  2. 线索标志:中序线索化过程中,每个节点有两个线索标志 ltag 和 rtag。在遍历过程中,如果 ltag 为 0,则表示左孩子指针指向的是实际的左子节点,需要继续递归遍历;如果为 1,则表示左孩子指针是指向中序前驱的线索。同样,rtag 用于指示右孩子指针是否为线索。

  3. 遍历顺序:中序遍历的顺序是左-根-右。这意味着在访问任何一个节点之前,它的左子树已经完全遍历并线索化,而它的右子树尚未遍历。因此,设置左线索是安全的,因为它不会影响右子树的遍历。

后序线索化:

  1. 线索化时机:在后序线索化过程中,节点的左线索和右线索是在其后序遍历的相应位置设置的。与中序线索化类似,这意味着在设置线索时,子树的遍历已经完成。

  2. 线索标志:后序线索化同样使用线索标志来区分子节点指针和线索。在遍历过程中,如果 ltag 为 0,则表示左孩子指针指向实际的左子节点;如果为 1,则表示左孩子指针是指向后序前驱的线索。右线索的设置是在遍历右子树和根节点之后。

  3. 遍历顺序:后序遍历的顺序是左-右-根。在设置右线索之前,右子树已经被完全遍历和线索化,因此不会影响到后续的遍历过程。

总的来说,中序和后序线索化之所以不会遇到先序线索化中的死循环问题,是因为它们在设置线索时已经完成了子树的遍历,因此不会覆盖未遍历的子节点指针。而先序线索化则需要额外注意,因为线索化可能发生在遍历子树之前,如果不正确处理,就可能会覆盖子节点指针,导致死循环。

总结:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/50224.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux练习2

一、搭建nfs服务器,客户端可从服务端/share目录上传与下载文件 **服务端** 1、下载相关安装包 [rootserver ~]# yum install rpcbind -y [rootserver ~]# yum install nfs-utils -y 2、 创建共享文件夹/share并授予权限 [rootserver ~]# mkdir /share [rootserv…

vector以及迭代器失效

前言 学习完string,之后学习的就是vector。vector就是之前C语言中讲到过的顺序表,用三个变量分别记录资源的位置,容器的容量和容器中元素个数。原来的写法是直接使用指针加两个int变量,而标准库中,三个都是由指针确定的…

sql server 连接报错error 40

做个简单的记录,造成40 的原因有很多,你的错误并不一定就是我遇到的这种情况. 错误描述: 首先我在使用ssms 工具连接的时候是可以正常连接的,也能对数据库进行操作. 在使用 ef core 连接 Sql Server 时报错: Microsoft.Data.SqlClient.SqlException (0x80131904): A network-r…

hadoop学习(二)

一.MapReduce 1.1定义:是一个分布式运算程序的编程框架 1.2核心功能:将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在一个Hadoop集群上。 1.3优点 1)易于编程 它简单的实现一些接口&#…

【Linux】Ubuntu解决Release 文件已经过期问题

​今天在执行update更新软件包时遇到了此问题:E: http://cn.archive.ubuntu.com/ubuntu/dists/jammy-updates/InRelease 的 Release 文件已经过期(已经过期了 247天 21小时 33分 15秒)。该仓库的更新将不会应用,如图 ​ 这个报错之前其实经常遇到&#x…

电脑虚拟摄像头软件分享|用手机打破电脑摄像头的极限

随着手机摄像头的不断更新迭代,手机已经接近专业电脑摄像头的画质。这让我们可以花费更低的成本获取优质的电脑录像画面。今天小编给大家详细讲解电脑虚拟摄像头的在我们日常生活中的妙用,以及分享几款口碑不错的电脑虚拟摄像头软件。有需要的小伙伴可以…

Unity3D 转换微信小游戏指引 05 广告内购

Unity3D 转换微信小游戏指引系列(第五期 完结) 广告 在小程序后台页面找到推广->流量主 开通条件如下: 开通之后,需要接入广告组件。 调用创建广告组件的接口时,需要传入参数 adUnitId,这个是开通流量…

「C++系列」数组

文章目录 一、数组1. 声明数组2. 初始化数组3. 访问数组元素4. 遍历数组注意事项示例代码 二、多维数组1. 声明二维数组2. 初始化二维数组3. 访问二维数组元素4. 遍历二维数组注意事项示例代码 三、指向数组的指针1. 声明指向数组的指针2. 通过指针访问数组元素3. 指针和数组的…

Android 10.0 framework默认沉浸式状态栏功能实现

1. 前言 在10.0的系统rom定制化开发中,在实现状态栏的某些定制化开发中,在某些产品需要实现沉浸式状态栏,就是需要app 能全屏显示同样也能显示状态栏,接下来就来分析下相关的功能实现 如图: 2.framework默认沉浸式状态栏功能实现的核心类 frameworks\base\core\java\andro…

【神经网络】梯度下降的优化方法【数学公式+代码示例】

文章目录 1、简介2、指数加权平均2.1、公式2.2、代码 3、Momentum⭐3.1、公式演变3.2、代码 4、AdaGrad4.1、计算步骤4.2、代码示例 5、RMSProp5.1、公式5.2、代码5.3、小结 6、Adam6.1、公式和步骤解释⭐6.2、代码⭐6.3、优点 7、何为鞍点8、小结 🍃作者介绍&#…

国防科技大学深圳地区新生欢送会圆满举行

2024年7月28日,第97个八一建军节来临之际,在这个充满希望的盛夏时节,深圳地区迎来了13名即将踏入国防科技大学的优秀学子。 为了庆祝这一荣耀时刻,并表达对新生的深切祝福,在国防科技大学深圳校友会黄丹会长的积极倡议…

书生大模型实战营--L1关卡-Llamaindex RAG实践

一、安装llamaindex库 pip install llama-index pip install llama-index-embeddings-huggingface 二、问2024年巴黎奥运会 中国队获得几枚金牌,无法回答该问题 三、构建Llamaindex RAG 1、初始化llm 2、构建词向量模型 下载模型:git clone https://…

基于k8s快速搭建docker镜像服务的demo

基于k8s快速搭建docker镜像服务的demo 一、环境准备 如标题,你需要环境中有和2个平台,并且服务器上也已经安装好docker服务 接下来我来构建一个docker镜像,然后使用harbork8s来快速部署服务demo 二、部署概述 使用docker构建镜像&#x…

(2024,通用逼近定理(UAT),函数逼近,Kolmogorov–Arnold定理(KAT),任意深度/宽度的网络逼近)综述

A Survey on Universal Approximation Theorems 公和众与号:EDPJ(进 Q 交流群:922230617 或加 VX:CV_EDPJ 进 V 交流群) 目录 0. 摘要 1. 简介 2. 神经网络(NN) 3. 通用逼近定理&#xff0…

我的NAS是怎么连接Amazon Web Services S3的

作为IT爱好者,很多家庭都配备了Network Attached Storage(NAS),用于存储和管理大量数据。一个常见的挑战是如何实现异地备份,以确保数据的安全性和可恢复性。以下是一些解决方案和工具,可以帮助用户有效地管…

“手撕”MySQL的索引

目录 二、索引的作用 三、索引的缺点 四、如何使用索引 查看索引: 创建索引: ​编辑 删除索引: 五、索引的底层原理 那什么是B树,什么是B树呢? B树的好处: 总结: 一、什么是索引 索…

C语言的周末小练习(贰)

周末小练习&#xff1a; 5、输入身高和体重&#xff0c;计算BMI指数(BMI w/(h*h))。 #include <stdio.h>int main() {float w,h,BMI;/*printf("请输入体重\n");scanf("%f",&w);printf("请输入身高\n");scanf("%f",&h…

vue3 快速入门 (五) : Flex布局

1. 如何变成Flex布局 变成Flex容器&#xff0c;只需在容器布局的节点的CSS中&#xff0c;增加display : flex .mylayout {/* 省略了其他代码 */display: flex; }2. flex direction : 方向 row : 以行排列 row-reverse &#xff1a; 以行反向排列 column &#xff1a;以列排列…

Matlab编程资源库(11)多项式计算

一、多项式的四则运算 1&#xff0e;多项式的加减运算 2&#xff0e;多项式乘法运算 函数conv(P1,P2)用于求多项式P1和P2的乘积。 这里&#xff0c;P1、P2是两个多项式系数向量。 3&#xff0e;多项式除法 函数[Q,r]deconv(P1,P2)用于对多项式P1和P2作除法运算。其中Q返回多项…

【前端 09】JavaScript中的对象与JSON

JavaScript中的对象与JSON 在JavaScript中&#xff0c;对象和JSON&#xff08;JavaScript Object Notation&#xff09;是两个紧密相连但又有区别的概念。它们都在数据处理和交换中扮演着重要角色。本文将详细讲解JavaScript中的自定义对象以及JSON对象的基本概念、格式、用法…