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


一.树的逻辑结构:


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

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.mzph.cn/web/55183.shtml

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

相关文章

ASML业绩暴雷,股价一度跌超16%

KlipC报道:当地时间10月15日,阿斯麦(ASML)原定于周三公布的三季度业绩报告由于技术原因被短暂地提前公布,业绩报告显示,阿斯麦第三季度总净销售额75亿欧元,毛利率50.8%,净利润21亿欧…

社招高频面试题

1.单例模式 面试突击50:单例模式有几种写法? 2.Mybatis缓存机制 MyBatis的一、二级缓存查询关系 一级缓存是SqlSession级别,不能跨SqlSession共享,默认开启。 二级缓存是基于mapper namespace级别的,可以跨SqlSessi…

PetaLinux工程的常用命令——petalinux-create

petalinux-create&#xff1a;此命令创建新的PetaLinux项目或组件。 注&#xff1a;有些命令我没用过&#xff0c;瞎翻译有可能会翻译错了&#xff0c;像是和fpgamanager相关的部分。 用法: petalinux-create [options] <-t|--type <TYPE> <-n|--name <COMPONEN…

LeetCode:3039.进行操作使字符串为空(模拟 Java)

目录 3039.进行操作使字符串为空 题目描述&#xff1a; 实现代码与解析&#xff1a; 模拟 原理思路&#xff1a; 3039.进行操作使字符串为空 题目描述&#xff1a; 给你一个字符串 s 。 请你进行以下操作直到 s 为 空 &#xff1a; 每次操作 依次 遍历 a 到 z&#xff…

Mongodb 获取集合(collection)的统计信息

在MongoDB中&#xff0c;获取指定集合&#xff08;collection&#xff09;的统计信息可以通过执行collStats命令来实现。这个命令提供了关于集合的详细信息&#xff0c;包括&#xff1a; 集合的大小索引的大小和数量文档的数量存储空间的使用情况各种统计数据&#xff0c;如平…

[linux 驱动]gpio子系统详解与实战

目录 1 描述 1.1 文件节点操作 gpio 引脚 1.2 gpio 引脚计算 2 结构体 2.1 gpio_desc 2.2 gpio_device 2.3 gpio_chip 3 相关函数 3.1 goio 申请释放 3.1.1 gpio_request 3.1.2 gpio_free 3.2 gpio 输入输出设置 3.2.1 gpio_direction_input 3.2.2 gpio_direction…

filecoin filspark 检索

安装 boost 1、安装 YugabyteDB2、boostd-data 运行3、初始化 boostd4、运行 boostd5、运行 booster-http6、需要公网映射端口6.1 Libp2p 公网映射本地端口24001 发布矿工6.2 Graphql 公网映射本地端口8080 web界面6.3 IndexProvider.HttpPublisher 公网映射本地端口6700 http发…

微信小程序路由跳转的区别及其常见的使用场景

在微信小程序中&#xff0c;页面路由跳转的实现有几种常用方式&#xff0c;不同的跳转方式适用于不同的使用场景。下面是几种跳转方法的区别及其在实际项目中的应用场景。 1. wx.navigateTo 简介&#xff1a;保留当前页面并跳转到指定页面&#xff0c;最多保留10个页面的历史记…

Scala入门基础(10)高级函数

一.什么是高阶函数 二.map函数 三.foreach函数 四.filter函数 五.flatten函数 正文&#xff1a; 一.什么是高阶函数 高阶函数&#xff1a;是一个特殊的函数&#xff0c;特殊之处在于&#xff1a;它指使用其他函数作为参数或返回值 &#xff08;演示&#xff09; 二.map函…

Linux -- 初识动静态库

目录 为什么要有库&#xff1f; 静态库 什么是静态库&#xff1f; 特点 优点 缺点 动态库 什么是动态库&#xff1f; 优点 缺点 编译器会选择哪个库&#xff1f; 为什么要有库&#xff1f; 库的存在是为了提高软件开发的效率、促进代码复用以及简化维护工作。通过使用…

SpringSecurity(一)——认证实现

一、初步理解 SpringSecurity的原理其实就是一个过滤器链&#xff0c;内部包含了提供各种功能的过滤器。 当前系统中SpringSecurity过滤器链中有哪些过滤器及它们的顺序。 核心过滤器&#xff1a; &#xff08;认证&#xff09;UsernamePasswordAuthenticationFilter:负责处理…

js获取硬件设备

在Javascript中通过MediaDevices 的方法enumerateDevices() 请求一个可用的媒体输入和输出设备的列表&#xff0c;例如麦克风&#xff0c;摄像机&#xff0c;耳机设备等。返回的 Promise 完成时&#xff0c;会带有一个描述设备的 MediaDeviceInfo 的数组。通常你可以使用 navig…

python yolov8半自动标注

首先标注一部分图片&#xff0c;进行训练&#xff0c;生成模型&#xff0c;标注文件为xml方便后面统一做处理。 1、标注数据&#xff08;文件为xml, 转为txt用于训练&#xff0c;保留xml标签文件&#xff09; 2、模型训练&#xff08;训练配置、训练代码、&#xff09; 3、使用…

极狐GitLab 发布安全补丁版本 17.4.1、17.3.4、17.2.8

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…

[已解决]DockerTarBuilder永久解决镜像docker拉取异常问题

前阵子发现阿里云的docker加速镜像失效了&#xff08;甚至连nginx都拉取不了&#xff09;&#xff0c;重新换了并且加多了网络上比较常用的dokcer加速源&#xff0c;可以解决一部分问题&#xff0c;但仍然有一些镜像的某个版本或一些比较冷的镜像就是拉取不了&#xff0c;原因未…

Multiprocessing出错没有提示was skipped without notice in python

这个问题可以通过打印返回结果解决。 解决方法 比如 Pool.apply_async(csdnKuangXiaoHU, args=(p, DestFile))改成 Result = Pool.apply_async(csdnKuangXiaoHU, args=

『网络游戏』数据库表格转储【25】

避免勿删数据库表格&#xff0c;可以将表格存储 放到桌面即可 现在将表格删除后点击 浏览桌面表格保存即可 修改客户端脚本&#xff1a;NetSvc.cs 目的是在数据库更新异常时弹出提示以便修改 本章结束

进程间通信、无名管道、有名管道

一、进程 1.1 进程间通信的概念 线程通信通过全局变量即可。 进程间通信是相互独立的&#xff0c;但是所有进程都共用一份内核空间&#xff0c;所以进程和进程之间的通信可以通过内核去进行。 1.2 进程间通信方式 共7种: 传统的进程间通信方式&#xff1a; 无名管道有名管道…

suspend、suspendCancellableCoroutine、continuation-kotlin协程

0.首先整理协程的启动方法 在 Kotlin 中&#xff0c;启动协程的方法有多种&#xff0c;常用的方法包括 launch、async、和 runBlocking。每种方法有不同的用途和特性。以下是它们的详细介绍&#xff1a; 1. launch launch 是一个启动新协程的方法&#xff0c;返回一个 Job 对…

uniapp生成随机数

推荐学习文档 golang应用级os框架&#xff0c;欢迎stargolang应用级os框架使用案例&#xff0c;欢迎star案例&#xff1a;基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识&#xff0c;这里有免费的golang学习笔…