【数据结构】- 详解线索二叉树(C 语言实现)

目录

一、线索二叉树的基本概念

二、构造线索二叉树

三、遍历线索二叉树


 


一、线索二叉树的基本概念

遍历二叉树是以一定规则将二叉树中的结点排列成一个线性序列,得到二叉树中结点的先序序列、中序序列或后序序列。这实质上是对一个非线性结构进行线性化操作,使得每个结点(除第一个和最后一个外)在这些线性序列中有且仅有一个(直接)前序和(直接)后继

但是,当以二叉链表作为存储结构时,只能找到结点的左、右孩子信息,而不能直接得到结点在任一序列中的前驱和后继信息,这种信息只有在遍历的动态过程中才能得到,为此引入线索二叉树(Threaded Binary Tree)来保存这些动态过程中得到的有关前驱和后继的信息(线索化)。

虽然可以在每个结点中增加两个指针域来存放在遍历时得到的有关前驱和后继信息,但这样做使得结构的存储密度大大降低。由于有 n 个结点的二叉链表中必定有 n + 1 个空链域,因此可以利用这些空链域来存放结点的前驱和后继信息

试做如下规定:

  • 若结点有左子树,则左指针指向其左孩子,否则将左指针指向遍历序列中它的前驱结点

  • 若结点有右子树,则右指针指向其右孩子,否则将右指针指向遍历序列中它的后继结点

为了避免混淆,还需改变结点结构,增加两个标志域 ltag 和 rtag。当 ltag 和 rtag 为 0 时,表示 left 和 right 指向结点的左右孩子;当 ltag 和 rtag 为 1 时,表示 left 和 right 指向结点的前驱和后继

typedef struct ThrdBiTNode
{DataType data;struct ThrdBiTNode* left, * right;unsigned char ltag, rtag;  // 标志左右指针的类型,0 即非线索指针,1 即线索指针
}ThrdBiTNode;


二、构造线索二叉树

由于线索二叉树构造的实质是将二叉链表中的空指针改为指向前驱或后继的线索,而前驱或后继的信息只有在遍历时才能得到,因此线索化的过程即在遍历的过程中修改空指针的过程,可用递归算法。对二叉树按照不同的遍历次序进行线索化,可以得到不同的线索二叉树,包括先序线索二叉树、中序线索二叉树和后序线索二叉树。

下面重点介绍中序线索化的算法

为了记下遍历过程中访问结点的先后关系,附设一个指针 prev 始终指向刚刚访问过的结点,而指针 cur 指向当前访问的结点,由此记录下遍历过程中访问结点的先后关系。

快速创建一棵二叉树

ThrdBiTNode* BuyThrdBiTNode(DataType x)
{ThrdBiTNode* node = (ThrdBiTNode*)malloc(sizeof(ThrdBiTNode));if (NULL == node){perror("malloc failed!");return NULL;}node->data = x;node->left = node->right = NULL;node->ltag = node->rtag = 0;return node;
}
​
// 快速创建一棵二叉树
ThrdBiTNode* CreatedBiTree()
{ThrdBiTNode* node1 = BuyThrdBiTNode(1);ThrdBiTNode* node2 = BuyThrdBiTNode(2);ThrdBiTNode* node3 = BuyThrdBiTNode(3);ThrdBiTNode* node4 = BuyThrdBiTNode(4);ThrdBiTNode* node5 = BuyThrdBiTNode(5);ThrdBiTNode* node6 = BuyThrdBiTNode(6);
​node1->left = node2;node1->right = node3;node2->left = node4;node2->right = node5;node3->left = node6;
​return node1;
}

二叉树中序线索化

// 以结点 *cur 为根的子树中序线索化
void _InOrderThreading(ThrdBiTNode* cur, ThrdBiTNode** pprev)
{if (cur == NULL)return;
​_InOrderThreading(cur->left, pprev);  // 左子树递归线索化
​//【建立当前结点的前驱线索】// 如果当前结点的左指针为空,则将当前结点的左指针指向前驱结点if (cur->left == NULL){cur->left = *pprev;cur->ltag = 1;}//【建立前驱结点的后继线索】// 如果前驱结点的右指针为空,则将前驱结点的右指针指向当前结点if (*pprev != NULL && (*pprev)->right == NULL){(*pprev)->right = cur;(*pprev)->rtag = 1;}//【保持 prev 指向 cur 的前驱】*pprev = cur;_InOrderThreading(cur->right, pprev);  // 右子树递归线索化
}
​
// 二叉树中序线索化
void InOrderThreading(ThrdBiTNode* root)
{if (root == NULL)return;
​ThrdBiTNode* prev = NULL;_InOrderThreading(root, &prev);
​// 处理最后一个结点(最右结点)的右指针prev->right = NULL;prev->rtag = 1;
}

Test.c

#include "ThrdBiTree.h"
​
int main()
{ThrdBiTNode* root = CreatedBiTree();InOrderThreading(root);return 0;
}


三、遍历线索二叉树

由于有了结点的前驱和后继信息,线索二叉树的遍历和在指定次序下查找结点的前驱和后继算法都变得简单。因此,若需经常查找结点所在遍历线性序列中的前驱和后继,则采用线索链表作为存储结构。

下面分 3 种情况讨论在线索二叉树中如何查找结点的前驱和后继。

  1. 在中序线索二叉树中查找

    (1) 查找 cur 所指结点的前驱

    • 若 cur->ltag == 1,则结点的前驱为 cur->left 指向的结点;

    • 若 cur->ltag == 0,则说明 *cur 有左子树,结点的前驱是遍历左子树时最后访问的一个结点(即左子树中最右下的结点)

    对中序线索二叉树进行【逆向】中序遍历

    // 找到树中最后一个被中序遍历的结点(即最右下的结点)
    ThrdBiTNode* LastNode(ThrdBiTNode* p)
    {while (p->rtag == 0)p = p->right;return p;
    }
    ​
    // 在中序线索二叉树中找到 *cur 的前驱结点
    ThrdBiTNode* PrevNode(ThrdBiTNode* cur)
    {if (cur->ltag == 1)return cur->left;elsereturn LastNode(cur->left);
    }
    ​
    // 对中序线索二叉树进行【逆向】中序遍历
    void RevInOrder(ThrdBiTNode* root)
    {if (root == NULL){printf("\n");return;}
    ​ThrdBiTNode* cur = LastNode(root);while (cur != NULL){printf("%d ", cur->data);cur = PrevNode(cur);}printf("\n");
    }

    (2) 查找 cur 所指结点的后继

    • 若 cur->rtag == 1,则结点的后继为 cur->right 指向的结点;

    • 若 cur->rtag == 0,则说明 *cur 有右子树,结点的后继是遍历右子树时第一个访问的结点(即右子树中最左下的结点)

    对中序线索二叉树进行中序遍历(利用线索实现非递归算法)

    // 找到树中第一个被中序遍历的结点(即最左下的结点)
    ThrdBiTNode* FirstNode(ThrdBiTNode* p)
    {while (p->ltag == 0)p = p->left;return p;
    }
    ​
    // 在中序线索二叉树中找到 *cur 的后继结点
    ThrdBiTNode* NextNode(ThrdBiTNode* cur)
    {if (cur->rtag == 1)return cur->right;elsereturn FirstNode(cur->right);
    }
    ​
    // 对中序线索二叉树进行中序遍历 
    void InOrder(ThrdBiTNode* root)
    {if (root == NULL){return;printf("\n");}
    ​ThrdBiTNode* cur = FirstNode(root);while (cur != NULL){printf("%d ", cur->data);cur = NextNode(cur);}printf("\n");
    }
  2. 在先序线索二叉树中查找 cur 所指结点的后继

    • 若 cur->rtag == 1,则结点后继为 cur->right 指向的结点;

    • 若 cur->rtag == 0,则说明 *cur 有右子树。按先序遍历的规则可知,*cur 的后继必为其左子树的根(若存在)或右子树的根

  3. 在后序线索二叉树中查找 cur 所指结点的前驱

    • 若 cur->ltag == 1,则结点前驱为 cur->left 指向的结点;

    • 若 cur->ltag == 0,且 cur->rtag == 0,则说明 *cur 有右子树,此时结点后继为其右子树的根,即 cur->right 指向的结点;若 cur->rtag == 1,则说明 *cur 没有右子树,但有左子树,此时结点的后继为其左子树的根,即 cur->left 指向的结点

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

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

相关文章

深度学习毕设项目 深度学习 python opencv 动物识别与检测

文章目录 0 前言1 深度学习实现动物识别与检测2 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 3 YOLOV53.1 网络架构图3.2 输入端3.3 基准网络3.4 Neck网络3.5 Head输出层 4 数据集准备4.1 数据标注简介4.2 数据保存…

PHP微信UI在线聊天系统源码 客服私有即时通讯系统 附安装教程

DuckChat是一套完整的私有即时通讯解决方案,包含服务器端程序和各种客户端程序(包括iOS、Android、PC等)。通过DuckChat,站点管理员可以快速在自己的服务器上建立私有的即时通讯服务,用户可以使用客户端连接至此服务器…

LeetCode(42)有效的字母异位词【哈希表】【简单】

目录 1.题目2.答案3.提交结果截图 链接: 有效的字母异位词 1.题目 给定两个字符串 *s* 和 *t* ,编写一个函数来判断 *t* 是否是 *s* 的字母异位词。 **注意:**若 *s* 和 *t* 中每个字符出现的次数都相同,则称 *s* 和 *t* 互为字…

设计模式 【Adapter 模式】

Adapter 模式 1.什么是 Adapter 模式 用来填补现有的程序和所需的程序之间差异的设计模式就是 Adapter 模式。 Adapter 模式有两种: ● 类适配器模式,即使用继承的适配器 ● 对象适配器模式,即使用委托的适配器 2.使用继承的适配器示例…

TZOJ 1367 计算两点间的距离

答案&#xff1a; #include <stdio.h> #include<math.h> //引用数学的库函数 int main() {double x1 0.0, y1 0.0, x2 0.0, y2 0.0; //由于输入的是实数&#xff0c;实数包括小数&#xff0c;所以不能 用int类型&#xff0c;只能用double类型while (sc…

Vue性能优化方法

一、前言 1.1 为什么需要性能优化 用户体验&#xff1a;优化性能可以提升用户体验&#xff0c;降低加载时间和响应时间&#xff0c;让用户更快地看到页面内容。SEO优化&#xff1a;搜索引擎更喜欢快速响应的网站&#xff0c;优化性能可以提高网站的排名。节约成本&#xff1…

ubuntu16.04部署gitlab-runner触发gitlab流水线

环境&#xff1a;ubuntu16.04 gitlab服务器&#xff1a;192.168.1.12 runner服务器&#xff1a;192.168.1.11 1.下载 环境&#xff1a;192.168.1.11 cd /usr/local/srcwget https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.debsudo dpkg …

Pandas进阶:20个实用的Pandas函数的基本使用

1. ExcelWriter 很多时候dataframe里面有中文&#xff0c;如果直接输出到csv里&#xff0c;中文将显示乱码。而Excel就不一样了&#xff0c;ExcelWriter是pandas的一个类&#xff0c;可以使dataframe数据框直接输出到excel文件&#xff0c;并可以指定sheets名称。 df1 pd.Da…

人工智能在内容相关性Content Relevance方面的应用

许多公司在向客户和潜在客户提供内容服务时犯了一个错误&#xff0c;即定制性不足&#xff0c;内容过于通用&#xff0c;可能与每位目标客户都不相关。谈及内容相关性时&#xff0c;人们希望获得有用的信息和问题解决方法&#xff0c;或具有娱乐性和参与性的内容。 为客户提供…

对话式数据需求激增,景联文科技提供高质量多轮对话数据定制采集标注服务

大模型的快速发展使得数据服务需求激增&#xff0c;产品整体处于供不应求状态。对话式数据集成为当下需求热点&#xff0c;人们对于更复杂、更真实的多轮对话数据需求不断增加&#xff0c;定制化服务占据市场需求主流。 通过对多轮对话数据的训练&#xff0c;模型可以更好地理解…

Python Xorbits库:实现无限可能的编程旅程

概要 Python Xorbits是一个强大而多功能的开源Python库&#xff0c;为开发者提供了实现创新和复杂计算的能力。它提供了各种功能和工具&#xff0c;帮助开发者在编程旅程中探索无限可能。本文将详细介绍Python Xorbits的用途和使用教程&#xff0c;帮助读者了解和掌握这个令人…

GEE 23:基于GEE实现物种分布模型之随机森林法

基于GEE实现物种分布模型之随机森林法 1.物种分布数据2.研究区绘制3.预测因子选择 1.物种分布数据 根据研究目的和需要导入物种数据&#xff1a; // Load presence data var Data ee.FeatureCollection("users/************736/Distribution"); print(Original da…

web和微信小程序设置placeholder样式

文章目录 一、场景二、web2.1、概念2.2、用法2.3、样式 三、小程序四、最后 一、场景 在页面布局时经常会用到input输入框&#xff0c;有时为了提示用户输入正确的信息&#xff0c;需要用placeholder属性加以说明。 二、web 2.1、概念 placeholder 是HTML5 中新增的一个属性…

cocos creator-碰撞检测

碰撞检测文档 刚体自行选择&#xff0c;刚体正常设置分组、tag&#xff0c;tag用于区分是哪个物体被碰撞了 正常在一个node下挂载脚本就行 注意&#xff1a;Builtin 2D 物理模块只会发送 BEGIN_CONTACT 和 END_CONTACT 回调消息。ccclass(TestContactCallBack) export class …

NoSql非关系型数据库

前言&#xff1a;Nosql not only sql&#xff0c;意即“不仅仅是sql”&#xff0c;泛指非关系型数据库。这些类型的数据存储不需要固定的模式&#xff08;当然也有固定的模式&#xff09;&#xff0c;无需多余的操作就可以横向扩展。NoSql数据库中的数据是使用聚合模型来进行处…

A*算法学习

系列文章目录 前言 在总结 2023华为软件精英挑战赛——全赛段思路分享与总结 - 知乎 (zhihu.com)时&#xff0c;发现自己还有很多技术细节没搞懂&#xff0c;这里看静态全局路径规划最常见的A*算法&#xff0c;这个博主讲得很好&#xff1a; A-Star&#xff08;A*&#xff0…

基于谷歌Flutter的媒体资讯APP的设计与实现

基于谷歌Flutter框架媒体资讯App的设计与实现 摘要&#xff1a; 当今社会&#xff0c;随着经济和科技的发展&#xff0c;人们的生活节奏也愈来愈快&#xff0c;人们生活的阅读时间也越来越少&#xff0c;越发的流行碎片化阅读&#xff0c;而同样的对于互联网的客户端开发者&am…

目标检测常用评价指标

1 基本概念 1.1 IOU(Intersection over Union) 1.2 TP TN FP FN 2. 各种率 3. PR曲线 4. mAP的计算 4.1 AP的计算 4.2 mAP 4.3 mAP0.5和mAP0.5:0.95 1.1 IOU(Intersection over Union) 1.2 TP TN FP FN TP(Truth Positive)&#xff1a; 预测正类&#xff0c;实际正类&#x…

文件重命名:如何删除文件名中的下划线,特殊符号批量删除

在日常的工作中&#xff0c;经常会遇到文件名中包含特殊符号的情况&#xff0c;例如&#xff0c;一些文件名可能包含下划线、空格或其他特殊符号&#xff0c;这些符号可能会干扰我们的文件搜索和识别。此外&#xff0c;一些文件名可能包含无法识别的非标准字符&#xff0c;这可…

Neural Architecture Search for Deep Image Prior

深度图像先验的神经结构搜索 论文链接&#xff1a;https://arxiv.org/abs/2001.04776 项目链接&#xff1a;https://github.com/Pol22/NAS_DIP Abstract 在最近提出的深度图像先验算法(DIP)下&#xff0c;我们提出了一种神经结构搜索(NAS)技术来提高无监督图像去噪、修复和超…