数和森林(快来瞧)

news2024/9/28 19:22:08

森林的定义 

森林是由多颗互不相交的树所构成的树的集合,即森林包含多棵树,每一棵树都有自己的根结点。一棵树也可以看成森林。

 

树的表示及基本操作 

1.树(一般树)的表示方法

1.1树的双亲表示法

树的双亲表示法是将树的各个节点存储在一个数组中,每一个结点都与数组的下标唯一对应,在每个结点中记录其父结点的下标,根结点的父结点为-1。

(最左孩子结点:一个结点的孩子结点中位于最左边的孩子结点)

在实际应用中,树的双亲表示法可以简单地直接用两个数组data和pa表示,但需要指明结点的数量和根结点的下标。

注意:在树的双亲表示法中必须严格按照层次遍历的顺序进行编号。

#include<iostream>
using namespace std;
constexpr auto N = 30;
typedef char datatype;
struct paNode {
	int pa; //父结点的下标
	datatype data;
	paNode() :pa(-1) {};
};
typedef struct {
	paNode tree[N];
	int n;	//树中节点的数量
	int root;  //树的根结点下标
}paTree;

//双亲表示法的树的创建
paTree create_paTree(datatype data[N], int pa[N], int n) {
	paTree t;
	t.n = n;
	for (int i = 0; i < n; i++) {
		t.tree[i].pa = pa[i], t.tree[i].data = data[i];
		if (pa[i] == -1)
			t.root = i;
	}
}

//求双亲表示法的树中某个结点的最左孩子结点和右兄弟节点
//求树t中结点cur的最左孩子结点,结果作为返回值。如果cur为叶结点,则返回-1
int lm_child(paTree t, int cur) {
	for(int i = cur + 1; i < t.n; i++) {
		if (t.tree[i].pa == cur)
			return i; //cur的最左孩子结点为i
	}
	return -1;
}

//求树t中结点cur的右兄弟结点,结果作为返回值。如果cur没有右兄弟结点,则返回-1
int r_brother(paTree t, int cur) {
	if (cur < t.n && t.tree[cur + 1].pa == t.tree[cur].pa) {
		return cur + 1;
	}
	return -1;
}

int main() {

}

1.2树的左右链表示法

树的左右链表示法是指在树的每个结点中记录该结点的最左孩子结点和其右兄弟结点。这种表示方法中每个结点中应该包含节点的数据、结点的父节点、结点的最左孩子结点和结点的右兄弟节点。可以用链表表示,也可以用数组表示。

#include<iostream>
using namespace std;
constexpr auto N = 30;
typedef char datatype;

struct lrbNode {
	datatype data;
	int pa;
	int lmc; //最左孩子结点
	int rb; //右兄弟结点
	lrbNode() :lmc(-1), rb(-1) {};
};
typedef struct {
	lrbNode tree[N]; //结点表
	int n; //树的节点总数
	int root;//树的根结点下标
}lrbTree;

//树的孩子列表数组表示法的基本操作
//创建数,data为树的各结点的数据,pa为各结点的父节点,n为树的结点数
lrbTree create_lrbTree(datatype data[], int pa[], int n) {
	lrbTree t;
	t.n = n;
	for (int i = 0; i < n; i++) {
		t.tree[i].data = data[i];
		if (pa[i] == -1) t.root = i; //指定树的父节点
		else {
			t.tree[i].pa = pa[i];//指定结点i的父节点
			if (t.tree[pa[i]].lmc == -1)t.tree[pa[i]].lmc = i; //i为其父节点的第一个孩子结点
			else {
				t.tree[i - 1].rb = i; //i有左兄弟结点i-1,i即为i-1的右兄弟节点
			}
		}
	}
	return t;
}

//求树t中结点cur的最左孩子结点的下标,结果作为返回值
int lm_child(lrbTree t,int cur) {
	return t.tree[cur].lmc;
}

//求树t中结点cur的右兄弟的下标,结果作为函数返回值
int r_brother(lrbTree t, int cur) {
	return t.tree[cur].rb;
}

int main() {

}

树和森林的遍历

树的遍历 

 

#include<iostream>
using namespace std;
constexpr auto N = 30;
typedef char datatype;

struct lrbNode {
	datatype data;
	int pa;
	int lmc; //最左孩子结点
	int rb; //右兄弟结点
	lrbNode() :lmc(-1), rb(-1) {};
};
typedef struct {
	lrbNode tree[N]; //结点表
	int n; //树的节点总数
	int root;//树的根结点下标
}lrbTree;

//树的孩子列表数组表示法的基本操作
//创建数,data为树的各结点的数据,pa为各结点的父节点,n为树的结点数
lrbTree create_lrbTree(datatype data[], int pa[], int n) {
	lrbTree t;
	t.n = n;
	for (int i = 0; i < n; i++) {
		t.tree[i].data = data[i];
		if (pa[i] == -1) t.root = i; //指定树的父节点
		else {
			t.tree[i].pa = pa[i];//指定结点i的父节点
			if (t.tree[pa[i]].lmc == -1)t.tree[pa[i]].lmc = i; //i为其父节点的第一个孩子结点
			else {
				t.tree[i - 1].rb = i; //i有左兄弟结点i-1,i即为i-1的右兄弟节点
			}
		}
	}
	return t;
}

//求树t中结点cur的最左孩子结点的下标,结果作为返回值
int lm_child(lrbTree t, int cur) {
	return t.tree[cur].lmc;
}

//求树t中结点cur的右兄弟的下标,结果作为函数返回值
int r_brother(lrbTree t, int cur) {
	return t.tree[cur].rb;
}

//树的三种遍历方法
//对树t进行先根遍历,rt为当前子树的根结点
void preOrder(lrbTree t, int rt) {
	if (rt == -1)return;
	cout << t.tree[rt].data; //先访问根结点
	int cur = lm_child(t, rt); //根结点的最左孩子结点
	while (cur != -1) { //从树t的最左子树开始,依次先根遍历t的子树森林
		preOrder(t, cur);
		cur = r_brother(t, cur); //结点cur的右兄弟结点
	}
}

//对树t进行中根遍历,rt为当前子树的根结点
void midOrder(lrbTree t, int rt) {
	if (rt == -1)return;
	int cur = lm_child(t, rt); //根结点的最左孩子结点
	midOrder(t, cur);//中根遍历t的最左子树
	cout << t.tree[rt].data; //在t的最左子树遍历结束后访问根结点
	while (cur != -1) { //根结点的最左孩子结点
		cur = r_brother(t, cur);//结点cur的右兄弟结点
		midOrder(t, cur);
	}
}

//对树t进行后根遍历,rt为当前子树的根结点
void postOrder(lrbTree t, int rt) {
	if (rt == -1) return;
	int cur = lm_child(t, rt);  //根结点的最左孩子结点
	while (cur != -1) { //从t的最左孩子结点出发,依次后根遍历t的子树森林
		postOrder(t, cur);
		cur = r_brother(t, cur);  //结点cur的右兄弟结点
	}
	cout << t.tree[rt].data; //最终访问根结点
}

int main() {

}

树的括号表示法

【待补充】

森林的遍历【无代码演示】

森林有多颗树构成,每一棵树有一个根结点,可以定义一个辅助结点,森林中每颗子树的根结点作为其孩子结点,这样森林就变味一棵树,因此对森林的遍历可以转化为对树的遍历。

森林有如下两种遍历方法:
        先根遍历森林:从左到右依次先根遍历森林的各个子树。
        后根遍历森林:从左到右依次后根遍历森林的各个子树。

森林与二叉树的转换

森林树转换成二叉树后,对森林的操作都可以转换成对相应二叉树的操作。

森林转换成二叉树

 

参考:

二叉树与树、森林之间的转换_kindoms214的博客-CSDN博客_将二叉树转换成对应的树或森林icon-default.png?t=MBR7https://blog.csdn.net/kindoms214/article/details/85699598?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522167422309216800211583404%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=167422309216800211583404&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-85699598-null-null.142^v71^control_1,201^v4^add_ask&utm_term=%E4%BA%8C%E5%8F%89%E6%A0%91%E4%B8%8E%E6%A3%AE%E6%9E%97%E7%9A%84%E8%BD%AC%E6%8D%A2&spm=1018.2226.3001.4187 

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

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

相关文章

《牛客网刷题之零基础入门前端之CSS》

目录 CSS 选择器 FED9 CSS选择器——标签、类、ID选择器 FED10 CSS选择器——伪类选择器 FED11 CSS选择器——伪元素 样式设置 FED12 按要求写一个圆 FED13 设置盒子宽高 FED74 段落标识 FED75 设置文字颜色 FED76 圣诞树 布局 FED14 浮动和清除浮动 FED15 固定定…

LeetCode刷题模版:162、164-166、168

目录 简介162. 寻找峰值164. 最大间距【考查排序】165. 比较版本号166. 分数到小数168. Excel表列名称结语简介 Hello! 非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出~ ଘ(੭ˊᵕˋ)੭ 昵称:海轰 标签:程序猿|C++选手|学生 简介:因C语言结识编程,随后…

【GlobalMapper精品教程】041:从多波段影像中提取单波段方法

本实验讲解globalmapper中文24软件从多波段遥感影像中提取单波段方法。 参考阅读:【Envi风暴】Envi插件大全:多波段拆分工具的巧妙使用 文章目录 一、多波段影像介绍二、单波段提取方法一、多波段影像介绍 加载实验数据:打开GM软件,加载专栏配套实验数据包中的data041.rar…

第二章 IOC

1.IOC底层原理*什么是IOC&#xff1a;控制反转&#xff0c;把对象创建和对象之间的调用过程交给Spring进行管理*使用IOC的目的&#xff1a;降低耦合度*IOC底层原理&#xff1a;xml解析工厂模式反射*IOC思想基于IOC容器完成&#xff0c;IOC容器底层就是对象工厂*Spring提供IOC容…

【网络安全】WiFi密码爆破教程

WiFi密码爆破教程前言一、什么是暴力破解&#xff1f;二、准备破解工具1.VMware Pro 16 虚拟机安装2. VMware安装Kali Linux3. kali监听无限网卡三、WiFi密码暴力破解1. 虚拟机连接USB网卡2. 扫描附近WiFi3. 查看目标WiFi连接设备4. 抓包5. 破解前言 暴力破解攻击是指攻击者通…

代码随想录算法训练营第15天 102. 二叉树的层序遍历、226. 翻转二叉树

代码随想录算法训练营第15天| 102. 二叉树的层序遍历、226. 翻转二叉树 二叉树的层序遍历 学会二叉树的层序遍历&#xff0c;可以一口气打完以下十题&#xff1a; 102.二叉树的层序遍历107.二叉树的层次遍历II199.二叉树的右视图637.二叉树的层平均值429.N叉树的层序遍历515…

4-3指令系统-CISC和RISC

文章目录一.复杂指令系统计算机CISC二.精简指令系统计算机RISC三.CISC和RISC比较一.复杂指令系统计算机CISC 为增强原有指令的功能&#xff0c;设置更为复杂的新指令实现软件功能的硬化&#xff0c;这类机器成为复杂指令系统计算机CISC&#xff08;Complex Instruction Set Co…

Linux下的FTP服务器

目录 总体功能 功能1----------------查看服务器端的文件列表信息 功能2 ---------------从服务器段下载文件到客户端 功能3 ---------------向服务器端上传文件 功能4----------------客户端退出&#xff0c;服务器继续等待链接 总体功能 功能1----------------查看服务器…

STM32 SPI读写速度评估

目的&#xff1a;测试STM32H7 系列芯片的SPI读写速度。 测试环境&#xff1a;使用STM32H743, 逻辑分析仪&#xff0c; cubeIDE&#xff1b; 测试方法&#xff1a;使用了3种方法&#xff1a;软件IO模拟SPI&#xff0c; 软件控制CSMCU的SPI模块&#xff0c;完全使用SPI模块&…

Android 深入系统完全讲解(30)

下图是生命周期的说明图&#xff1a;如图可以看到&#xff1a; 当创建编解码器的时候处于未初始化状态。首先你需要调用 configure(…)方法让它处于 Configured 状态&#xff0c;然后调用 start()方法让其处于 Executing 状态。在 Executing 状态下&#xff0c;你就 可以使用…

LCHub:全新华为云Astro低代码平台,重塑企业数字化转型

为什么技术创新与业务突破难以挂钩?为什么寻求的卓越成果总难以实现?华为云Astro呈上解决之道,抓住重点一招致胜,让人人皆可高效开发,使创新按照你的步调进行。 华为云Astro低代码平台,重塑企业数字化转型 当企业倍受数字化升级困扰时,若仍延用传统编码开发,则会阻碍整…

Bootstrap4 之栅格系统

Bootstrap4 之栅格系统参考描述栅格系统&#xff08;网格系统&#xff09;原理容器.container 与视口宽度行列样式栅格等级网格宽度特点左对齐另起一行自适应布局对齐垂直对齐行列水平对齐排列响应式优先级偏移显隐参考 项目描述Bootstrap 入门经典珍妮弗、凯瑞恩Bootstrap 基…

内存屏障由来的理解和使用《编程高手必学的内存知识》学习笔记 Day 5

系列文章目录 这是本周期内系列打卡文章的所有文章的目录 《Go 并发数据结构和算法实践》学习笔记 Day 1《Go 并发数据结构和算法实践》学习笔记 Day 2《说透芯片》学习笔记 Day 3《深入浅出计算机组成原理》学习笔记 Day 4 文章目录系列文章目录前言一、概念理解&#xff08;…

JUC面试(六)——Java锁

Java锁 公平锁和非公平锁 概念 公平锁 是指多个线程按照申请锁的顺序来获取锁&#xff0c;类似于排队买饭&#xff0c;先来后到&#xff0c;先来先服务&#xff0c;就是公平的&#xff0c;也就是队列 非公平锁 是指多个线程获取锁的顺序&#xff0c;并不是按照申请锁的顺…

steam搬砖项目,每天1-2小时,月入1w+(内附教学资料)

steam搬砖就非常合适&#xff0c;最大的优点&#xff0c;操作性简单&#xff0c;0门槛也不用担心&#xff0c;一台电脑就能搞定。利用空余时间完成就可以 话不多说&#xff0c;先上目录&#xff0c;以便大家阅读~ 一.steam搬砖玩法 1、steam搬砖项目介绍 2、项目原理与产出…

ROS2机器人编程简述humble-第二章-Parameters .3.4

ROS2机器人编程简述humble-第二章-Launchers .3.3机器人程序通常需要配置各类参数&#xff0c;官网和一些书中都有介绍。概述ROS中的参数与各个节点相关。参数用于在启动时&#xff08;以及运行时&#xff09;配置节点&#xff0c;而无需更改代码。参数的生存期与节点的生存期相…

【区块链】深入剖析免费赚钱app的本质

你对免费赚钱软件好奇吗&#xff1f;前言一、揭开“免费赚钱app”神秘面纱1.常见的赚钱app2.app真的在做慈善吗&#xff1f;3.羊毛党的价值4.真正的游戏规则二、区块链1.哈希算法2.互联网挖矿三、深入探讨“区块链”的套路1.免费赚钱app真正的价值2.虚拟货币的本质3.虚拟货币泡…

Java设计模式-观察者模式/观察者模式适合那些场景?怎么使用

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 6.7 观察者模式 6.7.1 定义 又称发布-订阅模式&#xff0c;定义了一种一对多的依赖关系&#xff0c;让多个观察者对象同时监听某一个主题对象主体对象在状态变化…

[前端笔记——CSS] 9.CSS处理文件的标准流程+DOM

[前端笔记——CSS] 9.CSS处理文件的标准流程DOM1.CSS处理文件的标准流程2.关于DOM2.1 举个例子2.2 应用 CSS 到 DOM1.CSS处理文件的标准流程 当浏览器展示一个文件的时候&#xff0c;它必须兼顾文件的内容和文件的样式信息&#xff0c;CSS处理文件的标准流程如下&#xff1a; …

06_FreeRTOS临界区代码保护

目录 临界段代码保护简介 临界段代码保护函数介绍 任务级临界区函数详解 中断级临界区函数详解 临界段代码保护简介 什么是临界段:临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段 适用场合如: 1.外设:需严格按照时序初始化的外设:IIC、SPI等等 2.系统…