数据结构 树的存储和遍历
一、树的定义
树的定义
树型结构是⼀类重要的⾮线性数据结构。
• 有⼀个特殊的结点,称为根结点,根结点没有前驱结点。
• 除根结点外,其余结点被分成M个互不相交的集合T1 、T2 、...、Tm T,其中每⼀个集合⼜是⼀棵树,称这棵树为根节点的⼦树。
因此,树是递归定义的。
树的基本术语
• 结点的度:树中⼀个结点孩⼦的个数称为该结点的度。
• 树的度:树中结点最⼤的度数称为树的度。
• 树的⾼度(深度):树中结点的最⼤层数称为树的⾼度(深度)。
• 路径:树中两个结点之间的路径是由这两个结点之间所经过的结点序列构成的,路径⻓度为序列中边的个数。
有序树和⽆序树
• 有序树:结点的⼦树按照从左往右的顺序排列,不能更改。
• ⽆序树:结点的⼦树之间没有顺序,随意更改。
这个认知会在我们后续学习⼆叉树的时候⽤到,因为⼆叉树需要区分左右孩⼦。
有根树和⽆根树
• 有根树:树的根节点已知,是固定的。
• ⽆根树:树的根节点未知,谁都可以是根结点。
这个认知主要会影响我们对于树的存储。在存储树结构的时候,我们最重要的就是要存下逻辑关系。如果是⽆根树,⽗⼦关系不明确,此时我们需要把所有的情况都存下来。⽐如a和b之间有⼀条边,我们不仅要存a有⼀个孩⼦b,也要存b有⼀个孩⼦a。
甚⾄有的时候,在有根树的题⽬⾥,也要这样存储。
二、树的存储
孩⼦表⽰法:
孩⼦表⽰法是将每个结点的孩⼦信息存储下来。
如果是在⽆根树中,⽗⼦关系不明确,我们会将与该结点相连的所有的点都存储下来。
实现⽅式⼀:vector数组实现
案例:
题⽬描述:
给定⼀棵树,该树⼀共有n 个结点,编号分别是1 ∼ n 。
输⼊描述:
第⼀⾏⼀个整数n ,表⽰n 个结点。
接下来n − 1 ⾏,每⾏两个整数u, v ,表⽰u 和v 之间有⼀条边。vector是可变⻓数组,如果只涉及尾插,效率还是可以的。⽽树结构这种⼀对多的关系,正好可以利⽤尾插,把所有的关系全部存起来。
• 因此,可以创建⼀个⼤⼩为n + 1 的vector 数组edges[n + 1] 。
• 其中edges[i] ⾥⾯就保存着i 号结点所连接的结点。
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e5 + 10;
int n;
vector<int> edges[N]; // 存储树
int main()
{cin >> n;for(int i = 1; i < n; i++){int a, b; cin >> a >> b;// a 和 b 之间有⼀条边 edges[a].push_back(b);edges[b].push_back(a);}return 0;
}
实现⽅式⼆:链式前向星
链式前向星的本质就是⽤数组来模拟链表。
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
// 链式前向星
int h[N], e[N * 2], ne[N * 2], id;
int n;
// 其实就是把 b 头插到 a 所在的链表后⾯
void add(int a, int b)
{id++;e[id] = b;ne[id] = h[a];h[a] = id;
}
int main()
{cin >> n;for(int i = 1; i < n; i++){int a, b; cin >> a >> b;// a 和 b 之间有⼀条边 add(a, b); add(b, a);}return 0;
}
三、树的遍历
树的遍历就是不重不漏的将树中所有的点都扫描⼀遍。
在之前学过的线性结构中,遍历就很容易,直接从前往后扫描⼀遍即可。但是在树形结构中,如不
按照⼀定的规则遍历,就会漏掉或者重复遍历⼀些结点。因此,在树形结构中,要按照⼀定规则去遍历。常⽤的遍历⽅式有两种,⼀种是深度优先遍历,另⼀种是宽度优先遍历。
深度优先遍历-DFS
(⽤ppt展⽰,效果更佳)
深度优先遍历,英⽂缩写为DFS,全称是DepthFirstSearch,中⽂名是深度优先搜索,是⼀种⽤于遍历或搜索树或图的算法。所谓深度优先,就是说每次都尝试向更深的节点⾛,也就是⼀条路⾛到⿊。
具体流程:
1. 从根节点出发,依次遍历每⼀棵⼦树;
2. 遍历⼦树的时候,重复第⼀步。
因此,深度优先遍历是⼀种递归形式的遍历,可以⽤递归来实现。
案例:
题⽬描述:
给定⼀棵树,该树⼀共有n 个结点,编号分别是1~n 。
输⼊描述:
第⼀⾏⼀个整数n ,表⽰n 个结点。
接下来n − 1 ⾏,每⾏两个整数u, v ,表⽰u 和v 之间有⼀条边。
1、⽤vector数组存储
注:存储树结构的时候,会把相邻的所有结点都存下来,这样在扫描⼦树的时候会直接扫描到上⼀
层,这不是我们想要的结果。
因此,需要⼀个st 数组来标记,哪些结点已经访问过,接下来dfs 的时候,就不去遍历那些点
int n;
vector<int> edges[N]; // edges[i] 保存着 i 号结点相连的所有点
bool st[N]; // 标记当前结点是否已经被遍历过
// 当前遍历到 u 这棵⼦树
void dfs1(int u)
{// 先访问该点 cout << u << " ";st[u] = true; // 标记该点已经被访问过 // 访问它的⼦树 for(auto v : edges[u]){if(!st[v]) dfs1(v); // 如果没有遍历过,再去遍历 }
}
// ⽤ vector 数组
void test1()
{cin >> n;for(int i = 1; i <= n - 1; i++){int a, b; cin >> a >> b; // 读⼊⼀条边 edges[a].push_back(b); // 保存 a -> b 的⼀条边 edges[b].push_back(a); // 保存 b -> a 的⼀条边 }dfs1(1);
}
2、链式向前星存储
int n;
int h[N], e[N * 2], ne[N * 2], id;
bool st[N]; // 标记当前结点是否已经被遍历过
void add(int a, int b)
{id++;e[id] = b; // 搞⼀个格⼦,存 b // 把 b 头插在 a 这个链表的后⾯ ne[id] = h[a];h[a] = id;
}
// 当前遍历到 u 这棵⼦树
void dfs2(int u)
{cout << u << " ";st[u] = true;for(int i = h[u]; i; i = ne[i]){int v = e[i];if(!st[v]) dfs2(v);}
}
// ⽤数组模拟链表
void test2()
{cin >> n;for(int i = 1; i <= n - 1; i++){int a, b; cin >> a >> b;add(a, b); add(b, a);}dfs2(1);
}
宽度优先遍历-BFS
宽度优先遍历,英⽂缩写为BFS,全称是BreadthFirstSearch,也叫⼴度优先遍历。也是⼀种⽤于遍历或搜索树或图的算法。所谓宽度优先。就是每次都尝试访问同⼀层的节点。如果同⼀层都访问完了,再访问下⼀层。
算法过程可以看做是在树和图中,在起点放上⼀个细菌,每秒向周围的那些⼲净的位置扩散⼀层,直到把所有位置都感染。
具体实现⽅式:借助队列。
1. 初始化⼀个队列;
2. 根节点⼊队,同时标记该节点已经⼊队;
3. 当队列不为空时,拿出队头元素,访问,然后将队头元素的所有孩⼦⼊队,同时打上标记;
4. 重复3 过程,直到队列为空。
用vector实现:
int n;
vector<int> edges[N]; // edges[i] 保存着 i 号结点相连的所有点
bool st[N]; // 标记哪些点已经⼊过队了
void bfs1()
{queue<int> q;q.push(1);st[1] = true;while(q.size()){auto u = q.front(); q.pop();cout << u << " ";// 让孩⼦⼊队 for(auto v : edges[u])//把这点的孩子全部加入进来{if(!st[v]){q.push(v);st[v] = true;}}}
}
// ⽤ vector 数组
void test1()
{cin >> n;for(int i = 1; i <= n - 1; i++){int a, b; cin >> a >> b; // 读⼊⼀条边 edges[a].push_back(b); // 保存 a -> b 的⼀条边 edges[b].push_back(a); // 保存 b -> a 的⼀条边 }bfs1();
}
链式向前星存储:
int n;
int h[N], e[N * 2], ne[N * 2], id;
bool st[N]; // 标记哪些点已经⼊过队了
void add(int a, int b)
{id++;e[id] = b; // 搞⼀个格⼦,存 b // 把 b 头插在 a 这个链表的后⾯ ne[id] = h[a];h[a] = id;
}
void bfs2()
{queue<int> q;q.push(1);st[1] = true;while(q.size()){auto u = q.front(); q.pop();cout << u << " ";for(int i = h[u]; i; i = ne[i]){int v = e[i];if(!st[v]){q.push(v);st[v] = true;}}}
}
// ⽤数组模拟链表
void test2()
{cin >> n;for(int i = 1; i <= n - 1; i++){int a, b; cin >> a >> b;add(a, b); add(b, a);}bfs2();
}
相关文章:
数据结构 树的存储和遍历
一、树的定义 树的定义 树型结构是⼀类重要的⾮线性数据结构。 • 有⼀个特殊的结点,称为根结点,根结点没有前驱结点。 • 除根结点外,其余结点被分成M个互不相交的集合T1 、T2 、...、Tm T,其中每⼀个集合⼜是⼀棵树,…...
Jenkins项目CICD流程
Jenkins项目流程:1.配置git环境 git config --...2.把前后端的目录初始化位本地工作目录 #git init3.提交到本地git #git add ./ git commit -m "" git tag v14.然后提交到远程git(通过,用户,群组,项目,管理项目)git remote add origin http://...git push -…...
EasyRTC轻量级SDK:智能硬件音视频通信资源的高效利用方案
在智能硬件这片广袤天地里,每一份资源的精打细算都关乎产品的生死存亡。随着物联网技术的疾速演进,实时音视频通信功能已成为众多设备的标配。然而,硬件资源的捉襟见肘,让开发者们常常陷入两难境地。EasyRTC,以它的极致…...
AI Agent未来走向何方?
AI Agent未来走向何方? 目录 AI Agent未来走向何方?AI推理支撑应用开发走向新赛道智能体成为AI应用的主流形式大模型应用正以AI Agent的主流形式赋能终端设备从大到小AI模型发展从通用转向垂直:小型语言模型(SLM)AI推理支撑应用开发走向新赛道 训练与推理,是AI 大模型两大核…...
Visual Studio Code的键盘快捷键
注意:如果您在Mac上访问此页面,您将看到Mac的键盘快捷键。如果您使用Windows或Linux访问,您将看到该平台的密钥。如果您需要其他平台的键盘快捷键,请将鼠标悬停在您感兴趣的键上。 键盘快捷键编辑器 VS Code通过键盘快捷键编辑器…...
【Jenkins流水线搭建】
Jenkins流水线搭建 01、SpringBoot项目 - Jenkins基于Jar持续集成搭建文档基于手动方式发布项目基于dockerfile基于jenkins + dockerfile + jenkinsfile +pieline基于jenkins + jar方式的发布01、环境说明01、准备项目02、准备服务器03、安装git04、安装jdk1.805、安装maven依赖…...
PHP 基础介绍
PHP 学习资料 PHP 学习资料 PHP 学习资料 PHP 是一种广泛使用的开源服务器端脚本语言,尤其适合 Web 开发,能轻松嵌入 HTML 中,生成动态网页内容。接下来,让我们一起了解 PHP 的基础内容。 一、PHP 的安装与配置 在开始编写 PH…...
DeepSeek如何重塑我的编程学习:计算机新生的AI实践
目录 🚀前言🌟邂逅DeepSeek:从困惑到惊喜💯初学编程的困境💯DeepSeek的优势 🖊️DeepSeek在编程学习中的运用💯注释💯算法逐步分析💯调试帮助💯跨语言迁移学习…...
spring boot和spring cloud的关系
Spring Boot和Spring Cloud之间的关系可以概括为构建和扩展的关系,其中Spring Boot提供了基础,而Spring Cloud在此基础上提供了分布式系统和微服务架构所需的扩展和工具。以下是两者关系的详细阐述: 一、基础与扩展 Spring Boot:…...
ThreadLocal原理和存在问题
ThreadLocal 的工作原理 ThreadLocal 是 Java 提供的一个类,用于在多线程环境下存储线程局部变量。每个线程都可以独立地更改存储在其 ThreadLocal 变量中的值,而不会影响其他线程中的变量副本。ThreadLocal 的实现原理基于 Thread 类中的 ThreadLocal.…...
用Echarts的柱状图实现圆柱体效果
用Echarts的柱状图实现圆柱体效果 在数据可视化的世界里,Echarts凭借其强大的功能和丰富的特性,成为众多开发者的首选工具。本文将深入探讨如何利用Echarts的柱状图来实现独特的圆柱体效果,通过详细剖析代码,让大家了解其中的实现…...
Docker 常用命令基础详解(一)
一、Docker 初相识 在当今数字化时代,软件开发和部署的效率与灵活性成为了关键因素。Docker,作为一款开源的应用容器引擎,犹如一颗璀璨的明星,照亮了软件开发与部署的道路,为开发者们带来了前所未有的便利。它就像是一…...
Java并发中的CAS机制:原理、应用与挑战(通俗易懂版)
上一期文章内容:Java并发中的乐观锁与悲观锁, 本期文章我们来讲一下Java并发中的CAS机制 一、从银行账户案例理解CAS CAS 是一种乐观锁机制,用于在不使用锁的情况下实现多线程对共享资源的并发访问。 它包含三个操作数:内存位置&a…...
腾讯发布混元-3D 2.0: 首个开源高质3D-DiT生成大模型
在之前的文章中已经和大家介绍过腾讯HunYuan-3D 1.0,感兴趣的小伙伴可以点击下面链接阅读~ HunYuan-3D 是首个开源高质3D-DiT生成大模型,几何与纹理解藕生成,一键将创意具象化。 2.0模型架构图及介绍 2.0模型将几何和纹理生成解耦࿰…...
【机器学习】线性回归与一元线性回归
线性回归与一元线性回归 V1.1线性回归问题线性方程的最优解一元线性回归一元线性回归的方程一元线性回归距离衡量方法一元线性回归的最优化求解一元线性回归的最小二乘法解法 V1.1 线性回归问题 线性回归问题就是找一条线或超平面,并使用线或超平面来描述数据分布…...
哈希表-两个数的交集
代码随想录-刷题笔记 349. 两个数组的交集 - 力扣(LeetCode) 内容: 集合的使用 , 重复的数剔除掉,剩下的即为交集,最后加入数组即可。 class Solution {public int[] intersection(int[] nums1, int[] nums2) {Set<Integer…...
望远镜成像系统--科学评价光学镜头
望远镜是一种利用透镜或反射镜以及其他光学器件观测遥远物体的光学仪器。其原理是通过透镜的折射或反射镜的反射,将光线聚焦成像,再经过一个放大目镜进行观察。日常生活中的光学望远镜又称“天文望远镜”。1608年,荷兰的一位眼镜商汉斯利伯希…...
服务器延迟给视频网站造成的影响
在数字化时代中,网络视频已经成为人们日常娱乐和获取信息的重要平台,网络视频的流畅性会影响着用户的体验度,那么,当服务器出现延迟会对视频网站造成哪些影响呢?本文就来共同了解一下吧! 当所使用的服务器由…...
C++算法竞赛基础语法-9
快速排序是一种高效的排序算法,由C. A. R. Hoare在1960年提出,基本思想是分治法(Divide and Conquer)策略,通过递归将一个大问题分解为若干个较小的子问题,然后合并这些子问题的解来解决原始问题 快速排序…...
国产编辑器EverEdit - 极简追梦人的福音:迷你查找
1 迷你查找 1.1 应用场景 某些场景下,用户不希望调出复杂的查找对话框,此时可以使用迷你查找窗口。 1.2 使用方法 选择主菜单查找 -> 迷你查找,或使用快捷键Ctrl Alt F,会在右上角弹出迷你查找窗口,如下图所示…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
