数据结构-5.9.树的存储结构

news2024/11/28 21:53:43


一.树的逻辑结构:


二.双亲表示法(顺序存储):

1.树中除了根结点外每一颗树中的任意一个结点都只有一个父结点(双亲结点);

2.结点包括结点数据和指针;

3.上述图片中右边的顺序存储解析:比如A结点左边的0,就是在数组中的位置即第一个位置,A结点右边的-1代表没有双亲即没有父结点,结点C左边的2代表在数组中第3个位置,右边的0就是结点C的父结点即A结点在数组中的位置,其他同理;

4.上述图片中的代码解析:PTNode代表结点,结构体里的nodes数组是PTNode型,也就是结点的集合,构成了树,结构体PTNode里有结点的数据和指向双亲位置域的双亲指针,指针是int型(不是int *),因此指向的是双亲结点在数组中的位置下标;

5.基本操作:

a.增加结点:

上述图片增加一个结点M在结点H下,顺序存储在第12个位置即数组下标为11,结点M的父结点为H,结点H在数组中下标为7,因此结点M的结点指针parent为7:

此时数组中数据元素的排列顺序表面像是层序规则排列,但在插入新结点时并不需要遵守层序的规则即不需要同一层中必须先从最左边添加,然后依次添加到最右边,而是可以随意添加在某个结点下,比如再插入一个L结点在E结点下:

b.删除结点:

比如删除G结点,有两种方案:

方案一:把G结点的双亲指针改为-1(因为双亲指针的值就是对应结点的父结点在数组中的位置,此时G结点不存在了,即在该树中没有父结点,因此双亲指针可设为-1,是一个不存在的数组下标)

方案二:把尾部的数据即结点L里的数据移动到G结点的位置上,这样就保证数组里的每一个存储单元都是有效的(比方案一好)

注:删除结点后要把结点数减一,不是数组长度减一

刚才删除的G结点是叶子结点,如果删除的不是叶子结点,那么既然该结点被删除了,那么这个结点下面连着的所有结点即以该结点为根结点的树就都被删除了:如删除D结点,那么结点D,H,I,J,M就都被删除了,此时就涉及到查询除了根结点D外H,I,J,M在数组中的位置,然后更改双亲指针进行删除;

c.查询结点(查询到结点后也可以修改结点数据):

采用双亲表示法,找到父结点很容易,因为有双亲指针直接可以知道父结点在数组中的位置,

但如果找父结点的子结点,就只能从头到尾依次遍历,把每一个结点的双亲指针取出来,对比是否与父结点在数组中的下标相等,这也就暴露出删除结点中方案一是有些低效的,因为该方案中删除元素后会有双亲指针的无效数据,此时遍历数组时也会把这个无效数据一起遍历,降低了效率,因此删除结点中方案二较好,

6.回顾:二叉树的顺序存储(二叉树也是树,也可以用双亲表示法)


三.孩子表示法(顺序+链式存储结合):

1.核心:先利用顺序表开辟一个顺序存储空间即数组来存储各个结点里的数据,每个结点包含数据域和指向第一个子结点的指针

2.代码:

解析:结点CTBox结构体中存储数据和第一个孩子,链表struct CTNode中的各个结点其实只是保存了各个子结点的数组下标

对于上述代码呈现出的存储结构,可知找子结点很方便,但找双亲结点就较麻烦;


四.孩子兄弟表示法(链式存储):

1.代码:

解析:1.*firstchild指针可看作左指针,指向结点的第一个子结点(不一定叫左子结点,因为可能不是二叉树,但一定是第

一个结点),

*nextsibling指针可看作右指针,指向结点的第一个子结点的后面结点即右兄弟结点

(左孩子,不同层;右兄弟,同层)

(从物理上看,用孩子兄弟表示法保存的树形状上和二叉树一样,只不过左右指针的含义不同)

如根结点A(只有孩子没有同层的兄弟),结点A的*firstchild指针指向B结点,

由于B结点的右兄弟为C结点,所以结点B的 *nextsibling指针指向 C结点,

由于C结点的右兄弟为D结点,所以结点C的 *nextsibling指针指向D结点,

同理,结点B的第一个孩子为E结点,那么结点B的*firstchild指针指向E结点,

由于E结点的右兄弟为F结点,所以结点E的 *nextsibling指针指向 F结点,

结点E的第一个孩子为K结点,那么结点E的*firstchild指针指向K结点,

同理,结点C的第一个孩子为G结点,那么结点C的*firstchild指针指向G结点,

同理,结点D的第一个孩子为H结点,那么结点D的*firstchild指针指向H结点,

由于H结点的右兄弟为I结点,所以结点H的 *nextsibling指针指向 I结点,

由于I结点的右兄弟为J结点,所以结点I的 *nextsibling指针指向 J结点,

2.例如:二叉树转化为树

思路:要把二叉树看作是用二叉链表保存的树,左边的第一个结点是孩子,剩下的右边全是兄弟

首先A是根结点,A结点的左边第一个结点B为左孩子,可知在B的右边的结点C,F,L都是它的右兄弟,所以:

看以B为根结点的子树,D结点是B结点的左孩子,H结点连在D结点的右边,所以H结点是D结点的右兄弟,

同理,G结点是D结点的左孩子,后续同理,最终如下:


五.森林和二叉树的转换:

本质:用二叉树链表(孩子兄弟表示法)存储森林

核心:可以利用二叉链表的方式来存储森林,一个森林里有几个互不相交的树,首先把森林里的树都转换为二叉树,森林里的每一棵树在逻辑上看是平级的,因此可以把这些树的根结点看作兄弟结点,如果用二叉链表(孩子兄弟表示法)存储的话,右指针表示兄弟关系,因此可以把这些树的根结点用右指针连接起来:

例题:

把二叉树转换为森林:

思路:从根结点A出发,右边的结点C,F,L都是右兄弟,因此结点A,C,F,L是平级的兄弟关系,

因此结点A,C,F,L就是四棵互不相交的树的根结点,

对于A结点,第一个孩子为B结点,B结点没有右兄弟,C结点已经用了,这里无需处理C结点

对于B结点,第一个孩子为D结点,D结点没有右兄弟,

对于D结点,第一个孩子为G结点,D结点的右兄弟为H结点,因此B结点的右边连接H结点,

对于C结点,第一个孩子为E结点,F结点已经用了,这里无需处理F结点,

对于E结点,第一个孩子为I结点,E结点的右兄弟为J,因此C结点右边连接J结点,

对于F结点,第一个孩子为K结点,L结点已经用了,这里无需处理L结点,

对于L结点,左右没有连接任何东西,所以处理完毕:


六.总结:


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

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

相关文章

机器学习:知识蒸馏(Knowledge Distillation,KD)

知识蒸馏(Knowledge Distillation,KD)作为深度学习领域中的一种模型压缩技术,主要用于将大规模、复杂的神经网络模型(即教师模型)压缩为较小的、轻量化的模型(即学生模型)。在实际应…

Java基础 03

⭐输入法的原理:⭐ 1.输入法本质就是输入字符的编码 2. Unicode对应16位编码-->所有字符都是16进制(也就是16进制) 码点:一套编码表中,单个字符对应的代码串叫做“码点” 3.变量 Java中所有应用的变量都要声明且…

Python面向对象编程:继承和多态③

文章目录 一、继承1.1 什么是继承1.2 定义父类和子类1.3 子类重写父类的方法1.4 多继承 二、多态2.1 什么是多态2.2 多态的实现2.3 抽象类和接口 三、综合详细例子3.1 项目结构3.2 模块代码init.pyshape.pycircle.pyrectangle.py 3.3 主程序代码main.py 3.4 运行结果 四、总结 …

实用篇—高效批量复制INSERT语句,并去除某列

在数据库管理中,常常需要将数据从一个表复制到另一个表。使用 Navicat 等工具可以方便地导出多条 INSERT 语句,但有时我们不需要某些列(如 ID 列)。本文将介绍如何在 Navicat 中复制多条 INSERT 语句,并去除 ID 列以便…

C语言笔记 14

函数原型 函数的先后关系 我们把自己定义的函数isPrime()写在main函数上面 是因为C的编译器自上而下顺序分析你的代码,在看到isPrime的时候,它需要知道isPrime()的样子——也就是isPrime()要几个参数,每个参数的类型如何,返回什么…

python画图|在三维空间的不同平面上分别绘制不同类型二维图

【1】引言 前序已经完成了基础的二维图和三维图绘制教程探索,可直达的链接包括但不限于: python画图|3D参数化图形输出-CSDN博客 python画三角函数图|小白入门级教程_正余弦函数画图python-CSDN博客 在学习过程中,发现一个案例&#xff1…

XGBoost回归预测 | MATLAB实现XGBoost极限梯度提升树多输入单输出

回归预测 | MATLAB实现XGBoost极限梯度提升树多输入单输出 目录 回归预测 | MATLAB实现XGBoost极限梯度提升树多输入单输出预测效果基本介绍模型描述程序设计参考资料预测效果 基本介绍 XGBoost的全称是eXtreme Gradient Boosting,它是经过优化的分布式梯度提升库,旨在高效、…

优化UVM环境(三)-环境发包较多时,会触发timeout

书接上回: 优化UVM环境(一)-环境结束靠的是timeout,而不是正常的objection结束 优化UVM环境(二)-将error/fatal红色字体打印,pass绿色字体打印 环境发包较多时,会触发timeout 解决…

SpringBoot +Vue3前后端分离项目入门基础实例五

项目说明 项项目名称使用框架说明后端项目springboot_vue_element_demoSpringBoot + MyBatis-plus + MySQL完成基本的增删改查操作API前端项目vue-projectVue3 + ElementUI plus + axios界面展示,调用后端API项目文档目录 SpringBoot +Vue3前后端分离项目入门基础实例一 Spri…

机器学习:opencv--人脸检测以及微笑检测

目录 前言 一、人脸检测的原理 1.特征提取 2.分类器 二、代码实现 1.图片预处理 2.加载分类器 3.进行人脸识别 4.标注人脸及显示 三、微笑检测 前言 人脸检测是计算机视觉中的一个重要任务,旨在自动识别图像或视频中的人脸。它可以用于多种应用&#xff0…

【C++】- STL之vector模拟实现

1.vector的介绍 vector是表示可变大小数组的序列容器。vector采用的连续存储空间来存储元素。意味着也可以采用下标对vector的元素进行访问,和数组一样高效。但是它的大小是可以动态改变的,而且它的大小会被容器自动处理。vector使用动态分配数组来存储它…

三子棋(C 语言)

目录 一、游戏设计的整体思路二、各个步骤的代码实现1. 菜单及循环选择的实现2. 棋盘的初始化和显示3. 轮流下棋及结果判断实现4. 结果判断实现 三、所有代码四、总结 一、游戏设计的整体思路 (1)提供一个菜单让玩家选择人机对战、玩家对战或者退出游戏…

企业电子印章主要通过以下几种方式进行防伪

企业电子印章主要通过以下几种方式进行防伪: 一、数字证书和加密技术 数字证书认证 企业电子印章依托数字证书,数字证书由权威的第三方数字认证机构颁发,确保了印章使用者的身份真实性。 数字证书如同企业在数字世界的身份证,包…

Python 工具库每日推荐 【sqlparse】

文章目录 引言SQL解析工具的重要性今日推荐:sqlparse工具库主要功能:使用场景:安装与配置快速上手示例代码代码解释实际应用案例案例:SQL查询分析器案例分析高级特性自定义格式化处理多个语句扩展阅读与资源优缺点分析优点:缺点:总结【 已更新完 Python工具库每日推荐 专…

SpringCloud-持久层框架MyBatis Plus的使用与原理详解

在现代微服务架构中,SpringCloud 是一个非常流行的解决方案。而在数据库操作层面,MyBatis Plus 作为 MyBatis 的增强工具,能够简化开发,提升效率,特别是在开发企业级应用和分布式系统时尤为有用。本文将详细介绍 MyBat…

我们是不是有点神话了OPENAI和CHATGPT?OPENAI真的Open?

网上很多人大力推荐和神化OPENAI的CHATGPT等产品,好像这神器无所不能!也不知道是VPN代理商为了给自己做广告?还是CHATGPT注册代理推销产品?或者有可能是国外宣传CHATGPT文章直接翻译过来的?不可否认CHATGPT确实是一款伟大的产品,但有些情况…

HarmonyOS的DevEcoStudio安装以及初步认识

目录 1.DevEco下载 2.DevEco安装 3. 未开启Hyper-V 1--开启Hyper-v流程 4.编译错误 5.目录结构 1)AppScope 2)entry: 3)build 4)entry->src 5)entry->src->main->etc 6)entry->src->main…

Shell编程-if和else

作者介绍:简历上没有一个精通的运维工程师。希望大家多多关注作者,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 我们前面学习了那么多命令,以及涉及到部分逻辑判断的问题。从简单来说,他就是Shell编程,…

一键快捷回复软件助力客服高效沟通

双十一临近,电商大战一触即发!在这个购物狂欢的热潮中,客服团队的效率至关重要。今天我要和大家分享一个非常实用的快捷回复软件,特别是为电商客服小伙伴们准备的。这款软件能够极大地提高你的工作效率,让你在处理客户…

小程序开发设计-模板与配置:WXML模板语法⑨

上一篇文章导航: 小程序开发设计-协同工作和发布:协同工作⑧-CSDN博客https://blog.csdn.net/qq_60872637/article/details/142455703?spm1001.2014.3001.5501 注:不同版本选项有所不同,并无大碍。 目录 上一篇文章导航&…