【数据结构】5.6 树和森林

news2024/11/24 13:58:10

文章目录

  • 5.6.1 树的存储结构(不是二叉树)
    • 双亲表示法
    • 孩子表示法
      • 结构定义
      • 双亲孩子法
    • 孩子兄弟法
  • 5.6.2 二叉树的转换
    • 树与二叉树的转换
      • 将树转换成二叉树
      • 将二叉树转换成树
    • 森林与二叉树的转换
      • 森林转换成二叉树
      • 二叉树转换成森林
  • 5.6.3 树和森林的遍历
    • 树的遍历
    • 森林的遍历

在这里插入图片描述

  • 如果将一棵树去掉根节点,那么这棵树就变成一片森林。
  • 反之,将森林中的所有的树加上一个统一的根结点,就变成了树。

5.6.1 树的存储结构(不是二叉树)

双亲表示法

  • 以一组连续的存储单元存储树的结点,每个结点除了数据域 data 之外,还附加一个 parent 域用来指向其双亲结点的位置。
  • 找双亲容易,找孩子难

实现

定义结构数组存放树的结点,每个结点包含两个域:

  • 数据域:存放结点本身的信息。
  • 双亲域:指示本结点的双亲结点在数组中的位置。

例如

  • 根节点 R 没有双亲,所以双亲域存放-1。
  • ABC 的双亲域里存着的都是0,表示他们共同的双亲都是在数组下标0出的数据 R,以此类推。

在这里插入图片描述
在这里插入图片描述

类型定义

typedef struct PTNode
{
		TElemType data;//存放的结点当中的数据,元素类型取决于要存储的结点的元素类型。
		int parent;//存放结点双亲的所在位置的下标
		
}PTNode;

定义树结构数组

#define MAX_TREE_SIZE 100
typedef struct
{
		PTNode nodes[MAX_TREE_SIZE];//有100个PTNode类型的数组
		int r;//表示根结点的下标的位置
		int n;//记录总共存储了多少结点
		
}PTree;

孩子表示法

  • 由于树中每个结点都可能有多棵子树,则可以使用多重链表,即每个结点由多个指针域,其中每个指针域指向一棵子树的根节点。
  • 把每个结点的孩子结点排列起来,看成是一个线性表,用单链表存储,则 n 个结点有 n 个孩子链表(叶子的孩子链表为空表)。而 n 个头指针又组成一个线性表,用顺序表(含 n 个元素的结构数组)存储。
  • 找孩子容易,找双亲难

举个栗子

在这里插入图片描述

如上图所示:

  • 根节点 R 的孩子是 ABC,那么就把它的孩子看成是一个线性表。
  • 将 ABC 用一个单链表穿起来。数据域用来存放数据元素,指针域则存放后继结点的地址。

在这里插入图片描述

  • 其他结点的孩子则以此类推依次用单链表串起来。
  • 用数组来存储每个单链表的头指针

在这里插入图片描述

根节点 R 在下标为 r = 4 的位置,总共有 n = 10 个结点

结构定义

孩子结点结构

在这里插入图片描述

typedef struct CTNode
{
		int child;
		struct CTNode *next;
		
}*ChildPtr;

双亲结点结构

在这里插入图片描述

typedef struct
{
		TElemType data;
		ChildPtr firstchild;//孩子链表的头指针,这个指针指向的类型是有两个成员所构成的孩子结点结构。
		
}CTBox;

树结构

typedef struct
{
		CTBox nodes[MAX_TREE_SIZE];//用来存放所有指向孩子链表的头指针
		int r;//表示根节点所在数组位置的下标
		int n;//表示该树有多少个结点
		
}CTree;

双亲孩子法

  • 由前面两种表示法知道,要么不好找孩子,要么不好找双亲,这个时候就需要一种既能找爸爸又能找孩子的表示法。
  • 可以将双亲法与孩子表结合起来,变成孩子双亲法在结构数组中再增加一个成员用来存储每个结点的双亲结点的下标
  • 这种结构就称为带双亲的孩子链表

在这里插入图片描述

孩子兄弟法

  • 又称为二叉树表示法,或二叉链表表示法,即以二叉链表做树的存储结构。
  • 链表中结点的两个链域分别指向该结点的第一个孩子以及下一个兄弟结点左孩右兄)。
  • 找孩子兄弟容易,找双亲困难

结构定义

//树的二叉链表(孩子-兄弟)存储表示
typedef struct CSNode
{
	ElemType data;//data存储的元素是什么类型它就是什么类型
	struct CSNode* firstchild ;//指向结点的第一个孩子
	struct CSNode* nextsibling;//指向节点的下一个兄弟

}CSNode,*CSTree;

举个栗子

在这里插入图片描述

  1. 根节点 R 的左指针域存储它的第一个孩子 A 的地址,因为 R 没有兄弟,所以右指针域为NULL。
  2. A 左指针指向它的第一个孩子 D,右指针指向它从左往右数的下一个兄弟 B。
  3. 其余结点以此类推。
  4. 从左往右斜着看在一条线上的都是兄弟,反之从右往左斜着看在一条线上的则是孩子双亲

5.6.2 二叉树的转换

树与二叉树的转换

  • 将树转化为二叉树进行处理,利用二叉树的算法来实现对树的操作。
  • 由于树和二叉树都可以用二叉链表作存储结构,则以二叉链表作媒介可以导出树与二叉树之间的一个对应关系。

将树以二叉链表的形式存储

在这里插入图片描述

  • 左指针域指向结点的第一个孩子,右指针域则指向结点的下一个兄弟。
    • A 结点的第一个孩子是 B,A 是根节点没有兄弟。
    • B 没有孩子,它的下个兄弟是 C。
    • C 的第一个孩子是 D,下个兄弟是 E。
    • D 既没有孩子也没用兄弟。

让一棵二叉树存储成二叉链表是同样的结构

  • 每个结点的左右指针域分别存储该结点的左右孩子

在这里插入图片描述

总结

在这里插入图片描述

上图的 树与二叉树,具有相同的二叉链表存储结构,那么就可以:

  • 把一棵 树 进行存储得到二叉链表,然后将二叉链表解释成二叉树对应的存储形式,就可以得到二叉树了。
  • 同理,将这棵 二叉树 存储得到二叉链表,然后将二叉链表解释成树对应的存储形式,就可以得到二叉树了。
  • 以中间的这个存储结构作为媒介,就可以找到树与二叉树之间的对应关系。
  • 给定一棵树,可以找到唯一的一棵二叉树与之对应

规律:在树中的兄弟结点到了二叉树中变成了右孩子左变右兄弟变儿子,右变左儿子变兄弟

将树转换成二叉树

  1. 加线:在兄弟之间加一条线
  2. 抹线:对每个结点,只保留双亲与第一个孩子之间的连线,其余连线全部消除。
  3. 旋转:以树的根节点为轴心,将整棵树顺时针转 45°。

树变二叉树兄弟相连留长子

举个栗子

将这棵树转换成二叉树,兄弟相连留长子

在这里插入图片描述

  1. 连线:兄弟之间要连线

在这里插入图片描述

  1. 抹线:只保留双亲结点与其第一个孩子之间的连线。

在这里插入图片描述
在这里插入图片描述

  1. 旋转:以树的根结点为轴,顺时针转 45°。

在这里插入图片描述

将二叉树转换成树

既然可以将树通过兄弟相连留长子这个方法转换成二叉树,那么同样可以将这个方法逆转得到二叉树。

  1. 加线:若 p 结点是双亲结点的左孩子,则将 p 的右孩子,右孩子的右孩子…沿着分支找到所有的右孩子,都与 p 的双亲用线连接起来。
  2. 抹线:抹掉原来二叉树中双亲结点与右孩子之间的连线
  3. 调整:将结点按照层次排列,形成树结构。

二叉树变树左孩右右连双亲,去掉原来右孩线

举个例子

将这棵二叉树转换成树,左孩右右连双亲,去掉原来右孩线

在这里插入图片描述

  1. 加线:B 为 A 的左孩子,将 B 的右右右孩子每个都与 A 连起来,其余结点同理。

在这里插入图片描述

  1. 抹线:去掉原来的二叉树中双亲结点与右孩子之间的连线,(加了几根线就去掉几根线)。
    • 如:去掉B与C之间的线、去掉C与D之间的线、H与I之间的线…

在这里插入图片描述

  1. 调整:同一层的结点的孩子为同一层。
    • BCD 为第一层的结点 A 的孩子,放在第二层。
    • EFGHI 为第二层的结点的孩子,放在第三层。

在这里插入图片描述

森林与二叉树的转换

森林转换成二叉树

二叉树与多棵树之间的关系

  1. 将各棵树分别转换成二叉树
  2. 将每棵树的根结点用线相连。
  3. 以第一棵树的根结点为二叉树的根,再以根结点为轴心,顺时针旋转,构成二叉树型结构。

森林变二叉树树变二叉树根相连

举个栗子

在这里插入图片描述

  1. 通过兄弟相连留长子的方法将所有的树转换成二叉树。

在这里插入图片描述

  1. 所有的树变二叉树之后,将所有的二叉树的根 AEG 连在一条线上。

在这里插入图片描述

  1. 以第一棵树的根节点 A 作为整个二叉树的根,然后以这个根结点旋转,其余的根结点 EG 就变成了 A 的右孩子,以及右孩子的右孩子。

在这里插入图片描述

二叉树转换成森林

  1. 抹线: 将二叉树中根节点与其右孩子的连线,及沿右分支搜索到的所有右孩子间的连线全部抹掉(森林变二叉树时,根结点值留了个A剩下两个成了它的右孩子),使其变成独立的二叉树。
  2. 还原:将独立的二叉树还原成树。

二叉树变森林去掉全部右孩线,孤立二叉再还原

举个例子

在这里插入图片描述

去掉全部右孩线,孤立二叉再还原

  1. 抹线
    • 将根结点 A 与它的右孩子 E,以及右孩子 E 的右孩子 G之间的线抹除。
    • 如果还有右右右孩子,则继续顺着右分支抹线。

在这里插入图片描述

  1. 去掉所有的右孩子线之后整棵二叉树就变成了几棵独立的二叉树。

在这里插入图片描述

  1. 将独立的二叉树通过左孩右右连双亲,去掉原来右孩线,变成树
    • 将同一个结点的孩子放在同一层。

在这里插入图片描述

5.6.3 树和森林的遍历

树的遍历

  • 由于树的每个结点可以有多个子树,所以将根放在哪个位置上就无法确定,导致树没有中序遍历。
  • 只有先根遍历后根遍历以及层次遍历这三种遍历方法。

先根遍历

  • 若树不为空,则先访问根节点,然后依次先根遍历根的每棵子树。

后根遍历

  • 若树不为空,则先依次后根遍历每棵子树,然后访问根结点。

层次遍历

  • 若树不为空,则按照自上而下,自左而右的顺序访问树中每个节点。

举个栗子

在这里插入图片描述

森林的遍历

将森林看作由三部分构成,分别遍历这三个部分。

  1. 森林中 第一棵树的根结点,
  2. 森林中 第一棵树的子树森林。
  3. 森林中 其他树构成的森林。

在这里插入图片描述

  • 先序遍历(123):如果首先遍历森林的第一部分,则称这种遍历为先序遍历
  • 中序遍历(213):如果首先遍历森林的第二部分,则称这种遍历为中序遍历

先序遍历

若森林不为空,则:

  1. 首先访问森林中第一棵树的根节点
  2. 先序遍历森林中第一棵树的子树森林。
  3. 先序遍历森林中(除第一棵树之外)其余树所构成的森林。

森林的先序:依次从左至右对森林中的每一棵树进行先根遍历

中序遍历

若森林不为空,则:

  1. 中序遍历森林中第一棵树的子树森林。
  2. 然后访问森林中第一棵树的根节点
  3. 中序遍历森林中(除第一棵树之外)其余树所构成的森林。

森林的中序:依次从左至右对森林中的每一棵树进行后根遍历(注意是后根遍历)。

举个栗子

在这里插入图片描述

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

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

相关文章

Nginx简介

一、什么是Nginx?Nginx是一个高性能的HTTP和反向代理Web服务器,同时也提供IMAP/POP3/SMTP服务。Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3/SMTP)代理服务器。Nginx的特点是:占有内存少,并发能…

JJWT实现令牌Token

登录实现方式 Session 详情: https://www.cnblogs.com/andy-zhou/p/5360107.html 会话的概念 会话就好比打电话,一次通话可以理解为一次会话。我们登录一个网站,在一个网站上不同的页面浏览,最后退出这个网站,也是…

【Java AWT 图形界面编程】Container 容器 ② ( Frame 窗口示例 | Panel 示例 | 窗口中文乱码处理 )

文章目录一、Frame 窗口示例二、Panel 示例三、窗口中文乱码处理一、Frame 窗口示例 首先 , 创建 Frame 实例对象 , 该对象就是 操作系统中应用软件的 窗口 ; // 1. 创建窗口 Frame frame new Frame("AWT 图形界面编程");Frame 是 Window 的子类 , public class F…

前端号外—2022年最受欢迎居然是它,Node.js危已

导读 | 2022年是艰难的一年,不仅有互联网的寒冬、还有新冠疫情的洗礼。但是似乎这一切都阻挡不了JavaScript的内卷,一年不长不短的时间中,JavaScript从创新、性能、功能等多维度深度进化,给前端带来了诸多惊喜。本文基于github上流…

仓库管理系统demo搭建指南

1、简介 1.1、案例简介 本文将介绍,如何搭建云进销存-仓库管理。 1.2、应用场景 云进销存-仓库管理应用分仓管理并提供灵活的库存计算方式及库存预警。 2、设置方法 2.1、表单搭建 1)新建表单【商品管理】,字段设置如下: …

TensorFlow笔记之神经网络完成多分类任务

文章目录前言一、数据集调用二、Tensorflow1.x1.单隐藏层2.模型保存与调用三、Tensorflow2.x1.全连接层类2.keras建模总结前言 对TensorFlow笔记之单神经元完成多分类任务进行修改,在tf1.x与tf2.x中使用神经网络完成手写体数字识别多分类任务。 一、数据集调用 数…

10、Javaweb_Cookkie会话Session修改IDEA代码模板

修改IDEA代码模板 选择Setting... 找到要修改的代码模板,点击ok修改即可 使用模板创建方法 ,点击文件包,右键New选择文件类型 点击ok即可 创建完成 会话技术 1. 会话:一次会话中包含多次请求和响应。 * 一次会话:浏览器第一次给服务器资…

JAVA开发(web常见安全漏洞以及修复建议)

web安全常见漏洞修复建议:SQL注入规避 代码层最佳防御sql漏洞方案:使用预编译sql语句查询和绑定变量。(1)使用预编译语句,使用PDO需要注意不要将变量直接拼接到PDO语句中。所有的查询语句都使用数据库提供的参数化查询…

92、【树与二叉树】leetcode ——222. 完全二叉树的节点个数:普通二叉树求法+完全二叉树性质求法(C++版本)

题目描述 原题链接:222. 完全二叉树的节点个数 解题思路 1、普通二叉树节点个数求法 (1)迭代:层序遍历BFS 遍历一层获取一层结点 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode …

华为交换机、路由器设备批量配置端口方法步骤

华为交换机、路由器批量配置端口方法步骤 在现实工作中,如果要对多个端口做同样的配置,每个接口逐一进行相同的配置,很容易出错,而且造成大量重复工作。 配置端口组功能就可以解决这个问题啦。 你只需要将这些以太网接口加入同一…

HTML学习笔记(全)

HTML 文章目录HTML第一章——HTML 基础认识1. 1 基础补充1.1.1 网页组成1.1.2 代码如何转换成网页1.1.3 渲染引擎(了解)1.1.4 web 标准1.2 HTML 基础认知1. HTML的概念2. HTML页面固定结构3. **标签说明:**第二章——HTML基础语法2.1——注释…

国产linux操作系统——麒麟操作系统的来龙去脉

文章目录1、linux操作系统2、国产操作系统3、麒麟操作系统4、引用1、linux操作系统 目前市场主流的linux操作系统分类大致如此,国产操作系统的麒麟操作系统,底层比较杂,所以单独一类。 2、国产操作系统 排名日期截止到2022 这里提一下排名第…

科技云报道:从re:Invent 2022读懂亚马逊云科技的“生态棋局”

科技云报道原创。 懂棋的人都知道,下棋靠的是智力的角逐,也是气度的较量。 到了云计算发展的新时期,下棋的“人”已经变了,单靠一个人的智力解决不了N个用户的N种问题。 因此,近年来头部云厂商纷纷加大了对合作伙伴生…

centos7:jenkins+nodejs前端自动化部署

系统:centos7 nodejs版本:v16.18.1 npm版本:8.19.2 由于centos7最大只支持16.18.1版本,尽量让前端写代码时使用这个版本,linux系统如果要装高版本的node需要安装glibc库,很危险,尽量不要操作。 jenkin…

Hudi系列6:使用pyspark操作Hudi

文章目录前言一. pyspark连接hudi二. 创建表三. 插入数据四. 查询数据五. Time Travel查询六. 更新数据七. 增量查询八. 基于时间点查询九. 删除数据9.1 软删除9.2 硬删除十. 插入覆盖十一. Spark其它命令11.1 Alter Table11.2 Partition SQL Command参考:前言 软件版本Python…

低成本MEMS惯导系统的捷联惯导解算MATLAB仿真

低成本MEMS惯导系统的捷联惯导解算MATLAB仿真一、姿态角转换为四元数二、四元数转换为姿态角三、反对称阵四、位置更新五、姿态更新六、程序及数据主程序:子程序:数据及完整程序之前将高成本的捷联惯导忽略地球自转、圆锥曲线运动以及划桨运动等化简为可…

【学习笔记之Linux】工具之make/Makefile与git

make/Makefile: 背景知识: 一个工程中的源文件不计数,按类型、功能、模块分别放在若干个目录中,Makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,那些文件需要重新编…

电源《龙珠超:超级人造人》观后感

上周看了动画电影《龙珠超:超级人造人》,《龙珠》这个系列同《火影》、《死神》、《海贼王》和《名侦探柯南》等都存在了很长时间,不断在更新,都是非常好的IP,伴随着很多人走过童年,也是因为时间太长了,记得…

品牌打假,假货治理,有什么好的方法

品牌打假,清除渠道假货,可以提高消费者对品牌的满意度与忠诚度,增强经销商的经销信心,维护稳定的价格体系及经销体系,树立良好的品牌形象。 但是品牌在打假的过程中,由于经验、时间、方法、技术等方面的局…

测试开发 | 接口测试之HTTP 协议讲解

本文节选自霍格沃兹测试开发学社内部教材HTTP 协议是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP 是万维网的数据通信的基础。客户端向服务端发送 HTTP 请求,服务端则会在响应中返回所请求的数据。了解了 HTTP 协议,才能对接口测试进行更…