当前位置: 首页 > news >正文

蓝桥备赛(16)- 树

一、树的概念

1.1 树的定义

1)树型结构(一对多)是⼀类重要的非线性数据结构

2 )有⼀个特殊的结点,称为根结点,根结点没有前驱结点

3)除了根节点外 , 其余结点被分成 M(M > 0) 个互不相交的集合 T1  ,  T2.....Tm , 其中每个集合 Ti (  1   <= i <=  m)  又是一棵结构与树类似的子树 。 每棵子树的根节点有且只有一个前驱 , 可以有 0 个 或者多个后继 。 因此 , 树是递归定义的

1.2 树的基本术语

  • 结点的度 : 一个结点有几个孩子 --> 度就有多少 
  • 树的度 : 一棵树中 , 最大的结点的度称为树的度 
  • 父结点 / 双亲结点 : 若一个结点含有子节点 , 则这个结点称为其子节点的父结点 
  • 子节点 / 孩子结点 : 一个结点含有的子树的根结点称为该结点的子节点
  • 叶子结点 / 终端结点 : 度为 0 的结点称为叶节点 
  • 分支结点 / 非终端结点: 度不为0的结点 
  • 兄弟结点 : 具有相同父结点 相互成为兄弟结点 ( 亲兄弟 )
  • 结点的层次 : 从根开始定义起 , 根为 第一层 , 根的子结点为第二层 ,依次类推
  • 树的高度 或 深度 : 树中结点的最大层次 
  • 路径 : 一条从树中任意结点出发 , 沿父结点 --> 子结点 连接 ,达到任意结点 的序列

树的概念与结构-CSDN博客

1.3 有序树和无序树

1)有序树:结点的子树按照从左往右的顺序排列,不能更改
2)无序树:结点的子树之间没有顺序,随意更改。
这个认知会在我们后续学习二叉树的时候用到,因为二叉树需要区分左右孩子
在算法竞赛中 , 遇到的基本上都是无序树 , 也就是说 , 不需要考虑孩子结点的顺序

在有序树的视角中 , 上面两棵树 不相同 ;

但是在无序树的视角中 , 上面两棵树是相同的 。

1.4 有根树和无根树

1)有根树: 树的根节点已知,是固定的。
2)无根树:树的根节点未知,谁都可以是根结点

在有根树的视角中   , 根结点为 : A 

 在无根树的视角中   : 

无根树会导致父子关系不明确 , 在存储时候需要注意 。 在算法竞赛中 , 一般遇到的树一般都是无根树 , 即使有根树 , 也会存在父子关系未知的情况 。

二、树的存储

1)树结构相对线性结构来说就比较复杂 。存储时,既要保存值域,也要保存结点与结点之间的关系
2)实际中树有很多种存储方式:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法等。

2.1 孩子表示法

1) 对于每一个结点,只存储所有孩子的信息

注意:如果在无根树之中 , 如何知道谁是孩子 ? 谁是父亲呢?

---->  管他三七二十一  !!!直接把相连的结点都存储起来!!! 都给我存!起!来!

2.2 实现方式一:用vector数组实现

在算法中 , 一般会给出树结构都是有编号的  , 以简化我们的操作

上面的题目,虽然告知了根结点是 1 , 但是其他的结点之间的关系还是未知的 , 所以我们还是需要当成无序树来处理

1) 创建一个大小足够的 vector 数组 :vector<int> edges[10];

2)   对于 i 的孩子 , 直接 edges[i] .push_back 进去即可 。

#include <iostream>
#include <cstdio>
#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;edges[a].push_back(b);edges[b].push_back(a);  }return 0;
}

2.3 实现方式二:链式前向星

本质上就是用   链表存储  所有孩子 , 其中链表是用数组模拟实现的 。

#include <iostream>
#include <cstdio>
#include <vector>
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;add(a,b);add(b,a);}return 0;
}

2.4 总结

1)前者由于用到了容器 vector,实际运行起来相比较于后者更耗时,因为 vector 是动态实现的。
2)但是在如今的算法竞赛中,⼀般不会无聊到卡这种常数时间。也就是 vector 虽然慢,但不会因此而超时。

三、树的遍历

树的遍历就是不重不漏的将树中所有的点都扫描一遍
在之前学过的线性结构中,遍历就很容易,直接从前往后扫描⼀遍即可。但是在树形结构中, 如果不按照⼀定的规则遍历,就会漏掉或者重复遍历⼀些结点 。因此,在树形结构中,要按照⼀定规则去遍历。
常用的遍历方式有两种,一种是深度优先遍历,另一种是宽度优先遍历。
注意 !!!
树的遍历是许多关于树的算法的知识 , 一定要掌握啊!!!

3.1 深度优先遍历 -DFS

1)深度优先遍历(DFS -- Depth First Search) , 是一种用于遍历 或 搜索树或图的算法

2)每次尝试向更深的结点走  --> 一条路走到黑 !!!走到不能再走的时候 , 返回 , 继续走其他的路。

                                                              不撞南墙不回头!!!

 因此 , DFS 其实就是利用 递归的形式遍历 , 可以用递归来实现 !

3.1.1 用vector 数组存储

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;const int N = 1e5 + 10;
int n;
vector<int> edges[N];//存储图
bool st[N];//标记哪些点已经访问了 
//方法一:vector 实现 void dfs(int u)
{cout << u << " ";st[u] = true;//说明当前这个点已经访问过了//访问所有的孩子 for(auto v:edges[u]){if(!st[v]){dfs(v);}} 
}
int main()
{//建树cin >> n;for(int i = 1; i< n;i++){int a,b;cin >> a >> b;edges[a].push_back(b);edges[b].push_back(a);  } //深度优先遍历dfs(1); return 0;
}

3.1.2 链式向前星存储

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;const int N = 1e5 +10;
int id,h[N],e[N*2],ne[N*2];
int n;
bool st[N];//标记哪些点已经访问过了void add(int a,int b)
{id++;e[id] = b;ne[id] = h[a];h[a] = id;
}void dfs(int u)
{cout << u << " ";st[u] = true;for(int i = h[u];i; i = ne[i]){int v = e[i]; // 孩子if(!st[v])dfs(v); }
}
int main()
{//建树 cin >> n;for(int i = 1;i<n ; i++){int a,b;cin >> a >> b;add(a,b);add(b,a);}//深度优先遍历dfs(1); return 0;
}

与使用vectoc 存储的打印结果不同 , 因为vector 是尾插到数的后面 , 但是链式前向星是头插。

时间复杂度
简单估计⼀下,在 dfs 的整个过程中,会把树中所有的边扫描量两遍。边的数量为 n − 1 因此时间复杂度为 O(N) 。
空间复杂度:
最差情况下,结点个数为 n 的树,⾼度也是 n ,也就是变成⼀个链表。此时递归的深度也是 n 此时的空间复杂度为 O(N) 。

3.2 宽度优先遍历 - BFS

宽度优先遍历( BFS --- Breadth First Search),也叫广度优先遍历。也是⼀种用于遍 或搜索树或图的算法。 所谓宽度优先。就是每次都尝试访问同⼀层的节点。 如果同⼀层都访问完了,再访问下一层。
                                                      一层一层来

3.1.1 用vector 数组存储

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;const int N = 1e5 + 10;
bool st[N]; //标记哪一个点已经入队了
int n;
vector<int> edges[N]; void bfs()
{queue<int> q;q.push(1);st[1] = true;while(q.size()){int u = q.front() ;q.pop() ;cout << u << " ";for(auto v : edges[u]){if(!st[v])	{q.push(v);st[v] = true;}}	} 
}
int main()
{//建树 cin >> n;for(int i = 1 ;i< n ; i++){int a, b;cin >> a >> b;edges[a].push_back(b);edges[b].push_back(a);  }//宽度优先遍历bfs(); return 0;
}

3.1.2 链式向前星存储

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;const int N = 1e5 +10;
bool st[N];
int id,e[N*2],ne[N*2],h[N];
int n;void add(int a,int b)
{id++;e[id] = b;ne[id] = h[a];h[a] = id;
}
void bfs()
{queue<int> q;q.push(1);st[1] = true;while(q.size() ){int 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; }}}
}
int main()
{cin >> n;//建树for(int i = 1;i<n;i++){int a,b;cin >> a >> b;add(a,b);add(b,a);} bfs();return 0;
}

时间复杂度: 所有结点只会入队一次,然后出队一次,因此时间复杂度为 O(N
空间复杂度: 最坏情况下,所有的非根结点都在同⼀层,此时队列里面最多有 n-1 个元素,空间复杂度为 O(N)

相关文章:

蓝桥备赛(16)- 树

一、树的概念 1.1 树的定义 1&#xff09;树型结构&#xff08;一对多&#xff09;是⼀类重要的非线性数据结构 2 &#xff09;有⼀个特殊的结点&#xff0c;称为根结点&#xff0c;根结点没有前驱结点 3&#xff09;除了根节点外 &#xff0c; 其余结点被分成 M&#xff08;M…...

黑马测试mysql基础学习

视频来源&#xff1a;软件测试工程师所需的MySQL数据库技术&#xff0c;mysql系统精讲课后练习_哔哩哔哩_bilibili 环境准备&#xff1a; 虚拟机Linux服务器安装mysql数据库。本机安装Navicat。使Navicat连接虚拟机的数据库。&#xff08;麻烦一点的是Navicat连接虚拟机的数据…...

ROS2-话题学习

强烈推荐教程&#xff1a; 《ROS 2机器人开发从入门到实践》3.2.2订阅小说并合成语音_哔哩哔哩_bilibili 构建功能包 # create package demo_python_pkg ros2 pkg create --build-type ament_python --license Apache-2.0 demo_python_pkg 自己写的代码放在./demo_python_pkg/…...

C++指针的基本认识

1.数组做函数参数 首先,所有传递给函数的参数都是通过传值方式进行的,传递给函数的都是参数的一份拷贝。 接着,当传递的参数是一个指向某个变量的指针时,函数将对该指针执行间接访问操作(拷贝指针,并访问所指向的内容),则函数就可以修改指向的变量。 2.一维数组 数组名…...

TypeScript系列06-模块系统与命名空间

1. ES 模块与 CommonJS 互操作性 1.1 模块解析策略 TypeScript 提供多种模块解析策略&#xff0c;每种策略针对不同的运行环境和开发场景优化&#xff1a; // tsconfig.json {"compilerOptions": {"moduleResolution": "node16", // 或 "…...

Linux(Centos 7.6)命令详解:zip

1.命令作用 打包和压缩(存档)文件(package and compress (archive) files)&#xff1b;该程序用于打包一组文件进行分发&#xff1b;存档文件&#xff1b;通过临时压缩未使用的文件或目录来节省磁盘空间&#xff1b;且压缩文件可以在Linux、Windows 和 macOS中轻松提取。 2.命…...

es-使用easy-es时如何指定索引库

在对应的实体类中&#xff0c;通过注解IndexName指定。 如上图&#xff0c;指定的索引库就是problems&#xff0c;那么之后我使用easy-es时都是针对该索引库进行增删改查。...

Redis-主从架构

主从架构 主从架构什么是主从架构基本架构 复制机制的工作原理1. 全量复制&#xff08;Full Synchronization&#xff09;2. 部分复制&#xff08;Partial Synchronization&#xff09;3. PSYNC2机制&#xff08;Redis 4.0&#xff09; 主从架构的关键技术细节1. 复制积压缓冲区…...

Java数据结构第二十期:解构排序算法的艺术与科学(二)

专栏&#xff1a;Java数据结构秘籍 个人主页&#xff1a;手握风云 目录 一、常见排序算法的实现 1.1. 直接选择排序 1.2. 堆排序 1.3. 冒泡排序 1.4. 快速排序 一、常见排序算法的实现 1.1. 直接选择排序 每⼀次从待排序的数据元素中选出最小的⼀个元素&#xff0c;存放在…...

inkscape裁剪svg

参考https://blog.csdn.net/qq_46049113/article/details/123824888&#xff0c;但是上个博主没有图片&#xff0c;不太直观&#xff0c;我补上。 使用inkscape打开需要编辑的图片。 在左边导航栏&#xff0c;点击矩形工具&#xff0c;创建一个矩形包围你想要保留的内容。 如果…...

类加载器加载过程

今天我们就来深入了解一下Java中的类加载器以及它的加载过程。 一、什么是类加载器&#xff1f; 在Java中&#xff0c;类加载器&#xff08;Class Loader&#xff09;是一个非常重要的概念。它负责将类的字节码文件&#xff08;.class文件&#xff09;加载到Java虚拟机&#x…...

Git基础之基本操作

文件的四种状态 Untracked&#xff1a;未追踪&#xff0c;如新建的文件&#xff0c;在文件夹中&#xff0c;没有添加到git库&#xff0c;不参与版本控制&#xff0c;通过git add将状态变为staged Unmodify&#xff1a;文件已入库&#xff0c;未修改&#xff0c;即版本库中的文件…...

简单的 Python 示例,用于生成电影解说视频的第一人称独白解说文案

以下是一个简单的 Python 示例&#xff0c;用于生成电影解说视频的第一人称独白解说文案。这个示例使用了 OpenAI 的 GPT 模型&#xff0c;因为它在自然语言生成方面表现出色。 实现思路 安装必要的库&#xff1a;使用 openai 库与 OpenAI API 进行交互。设置 API 密钥&#…...

[Pycharm]创建解释器

仅以此文章来记录自己经常脑子抽忘记的地方 有时候我们在建好了一个项目以后&#xff0c;想要更换解释器。以新建conda解释器为例。 一、conda解释器 1.选择setting 2.选择Add Local Interpreter 3.type选则conda。如果你之前已经有了conda环境&#xff0c;和我一样选择了Gen…...

在 k8s中查看最大 CPU 和内存的极限

在 Kubernetes&#xff08;k8s&#xff09;中&#xff0c;你可以从不同层面查看最大 CPU 和内存的极限&#xff0c;下面为你详细介绍从节点和集群层面查看的方法。 查看节点的 CPU 和内存极限 节点的 CPU 和内存极限是指单个节点上可分配的最大资源量&#xff0c;可通过以下几…...

【Python】为什么要写__init__.py

文章目录 PackageA(__init__特性)应该往__init__.py里放什么东西&#xff1f;1、包的初始化2、管理包的公共接口3、包的信息 正常我们直接导入就可以执行&#xff0c;但是在package的时候&#xff0c;有一种__init__.py的特殊存在 引入moduleA.py&#xff0c;执行main.py&…...

【IPFS应用开发】IPFS播放器-上传助手

本系列文章是针对 https://blog.csdn.net/weixin_43668031/article/details/83962959 内容的实现所编写的。开发经历包括思考过程、重构和推翻重来。 基于IPFS的视频播上传助手发布 起源一、优势:二、劣势:三、未来展望:上传助手Demo版本发布公告欢迎体验!立即体验:http:/…...

单细胞多数据集整合和去除批次效应教程,代做各领域生信分析

单细胞多数据集整合和去除批次效应教程 每个数据集的数据分别单独进行读取单细胞数据构建Seurat分析对象 读取各种来源的单细胞数据构建Seurat分析对象的教程 做这一步的时候可以查看我这篇写的非常详细的教程文章&#xff1a; 【腾讯文档】单细胞分析步骤1读取各种来源格式…...

Windows控制台函数:移动光标位置函数SetConsoleCursorPosition()

目录 什么是 SetConsoleCursorPosition&#xff1f; 它长什么样&#xff1f; 什么是 COORD&#xff1f; 怎么用它&#xff1f; 它有什么用&#xff1f; 跟 C 标准库有什么不一样&#xff1f; 注意事项 再试一个有趣的例子 什么是 SetConsoleCursorPosition&#xff1f;…...

MyBatis-Plus 注解大全

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 MyBatis-Plus 注解大全 MyBatis-Plus 是基于 MyBatis 的增强工具&#xff0c;通过注解简化了单表 CRUD 操作和复杂查询的配置。以下是常用注解的分类及详细说…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列&#xff0c;以便知晓哪些列包含有价值的数据&#xff0c;…...

Java编程之桥接模式

定义 桥接模式&#xff08;Bridge Pattern&#xff09;属于结构型设计模式&#xff0c;它的核心意图是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式通过组合关系来替代继承关系&#xff0c;从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化

iOS 应用的发布流程一直是开发链路中最“苹果味”的环节&#xff1a;强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说&#xff0c;这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发&#xff08;例如 Flutter、React Na…...