数据结构 树的存储和遍历

一、树的定义

树的定义
树型结构是⼀类重要的⾮线性数据结构。
• 有⼀个特殊的结点,称为根结点,根结点没有前驱结点。
• 除根结点外,其余结点被分成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();
}

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

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

相关文章

PyTorch 混合精度训练中的警告处理与代码适配指南

在最近的 PyTorch 项目开发中&#xff0c;遇到了两个与混合精度训练相关的警告信息。这些警告主要涉及 torch.cuda.amp 模块的部分 API 已被标记为弃用&#xff08;deprecated&#xff09;。本文将详细介绍这些警告的原因、解决方法以及最佳实践。 警告内容 警告 1: torch.cud…

STM32自学记录(九)

STM32自学记录 文章目录 STM32自学记录前言一、DMA杂记二、实验1.学习视频2.复现代码 总结 前言 DMA 一、DMA杂记 DMA&#xff08;Direct Memory Access&#xff09;直接存储器存取 DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输&#xff0c;无须CPU干预&…

鸿蒙Harmony-UIAbility内状态-LocalStorage详细介绍

鸿蒙Harmony-UIAbility内状态-LocalStorage详细介绍 1.1 Localstorage的概念 LocalStorage是页面级的UI状态存储&#xff0c;通过Entry装饰器接收的参数可以在页面内共享同一个LocalStorage实例&#xff0c;LocalStorage也可以在UIAbility内&#xff0c;页面间共享状态 1.2 Lo…

SiliconCloud 支持deepseek,送2000w token

SiliconCloud SiliconCloud 邀请奖励持续进行&#xff0c;2000 万 Tokens 送不停&#xff01; 邀请好友赚 2000 万 Tokens&#xff1a;每成功邀请一位新用户通过手机号码注册&#xff0c;您将获得 2000 万 Tokens&#xff1b;注册即送 2000 万 Tokens&#xff1a;受邀好友作为…

ubuntu服务器部署

关闭欢迎消息 服务器安装好 ubuntu 系统后&#xff0c;进行终端登录&#xff0c;会显示出很多的欢迎消息 通过在用户的根目录下执行 touch .hushlogin 命令&#xff0c;再次登录终端就不会出现欢迎消息 修改hostname显示 修改 /etc/hostname 文件内容为主机名&#xff0c;保…

排序算法——人无完人

没有哪一个排序方法是完美的&#xff0c;对于不同的需求&#xff0c;排序算法各有自己的优势。金无足赤&#xff0c;人无完人。 &#xff08;这里不再重复所讲排序算法的实现&#xff0c;网上已有很多好的教学。&#xff09; 排序方法除了依靠时间复杂度和空间复杂度来区分&am…

3D模型可视化引擎HOOPS Visualize在桌面端的支持有哪些特点?

在数字化转型日益加速的今天&#xff0c;工业和工程领域的专业人员面临着越来越复杂的设计和数据分析需求。3D模型可视化技术应运而生&#xff0c;并成为了加速设计和制造流程的关键工具。作为业界领先的3D可视化引擎之一&#xff0c;HOOPS Visualize提供了一系列强大的桌面端支…

傅里叶变换推导

基本模型 假设在二维直角坐标系中&#xff0c;可以用相互垂直的基向量和表示&#xff1a; 假设&#xff1a; 假设在上的投影为&#xff0c;那么&#xff1a; 所以&#xff1a; 用公式表达&#xff1a; 但是在实际中&#xff0c;基向量和不一定长度都是1&#xff0c;重新推导一…

数据科学之数据管理|python for office

现如今&#xff0c;随着计算机的逐渐普及。现代化办公成为每个职场人必备的技能&#xff0c;本文档就来介绍&#xff0c;如何使用pytohn实现自动化办公。然而&#xff0c;自动化办公有时并不能减少工作量。自动化办公更适合批量处理文档。单一的文件&#xff0c;小金不建议使用…

【前端框架】Vue3 中 `setup` 函数的作用和使用方式

在 Vue 3 里&#xff0c;setup 函数是组合式 API 的核心入口&#xff0c;为开发者提供了更灵活、高效的组件逻辑组织方式。以下为你详细介绍其作用和使用方式&#xff1a; 作用 1. 初始化响应式数据 在 setup 函数中&#xff0c;我们能够使用 ref 和 reactive 等函数来创建响…

MySQL无法连接到本地localhost的解决办法2024.11.8

问题描述&#xff1a;我的MySQL可以远程连接服务器&#xff0c;但无法连接自己的localhost。 错误提示&#xff1a; 2003 - Cant connet to MySQL server on localhost(10061 "Unknown error")查找问题原因&#xff1a; 1. 检查环境变量是否正确&#xff1a;发现没…

STM32HAL库快速入门教程——常用外设学习(2)

目录 一、STM32HAL库开发&#xff08;8&#xff09;——CubeMX配置DMA 1.1、什么是DMA&#xff1f; 1.2、内存内存之间的传输&#xff08;单次&#xff09; ​编辑 1.3、内存外设之间的传输&#xff08;ADC&#xff09; 二、STM32HAL库开发&#xff08;9&#xff09;——…

LabVIEW与小众设备集成

在LabVIEW开发中&#xff0c;当面临控制如布鲁克OPUS红外光谱仪这类小众专业设备的需求&#xff0c;而厂家虽然提供了配套软件&#xff0c;但由于系统中还需要控制其他设备且不能使用厂商的软件时&#xff0c;必须依赖特定方法通过LabVIEW实现设备的控制。开发过程中&#xff0…

PyQt组态软件 拖拽设计界面测试

PyQt组态软件测试 最近在研究PyQt,尝试写个拖拽设计界面的组态软件&#xff0c;目前实现的功能如下&#xff1a; 支持拖入控件&#xff0c;鼠标拖动控件位置 拖动控件边缘修改控件大小支持属性编辑器&#xff0c;修改当前选中控件的属性 拖动框选控件&#xff0c;点选控件 控…

AI如何与DevOps集成,提升软件质量效能

随着技术的不断演进&#xff0c;DevOps和AI的融合成为推动软件开发质量提升的重要力量。传统的DevOps已经为软件交付速度和可靠性打下了坚实的基础&#xff0c;而随着AI技术的加入&#xff0c;DevOps流程不仅能提升效率&#xff0c;还能在质量保障、缺陷预测、自动化测试等方面…

Mac配置Flutter开发环境

1、访问 Flutter 官网&#xff0c;下载安装Flutter SDK 2、将 Flutter 添加到 PATH 环境变量 找到用户文件夹中的.zshrc隐藏文件&#xff08;隐藏文件显示方式&#xff1a;shiftcommand.&#xff09;&#xff0c;打开.zshrc文件&#xff0c;添加Flutter SDK路径&#xff0c;注…

Linux系统使用ollama本地安装部署DeepSeekR1 + open-webui

Linux系统使用ollama本地安装部署DeepSeekR1 open-webui 1. 首先&#xff0c;下载安装ollama #下载安装脚本并执行 curl -fsSL https://ollama.com/install.sh | sh #安装完成后查看ollama版本 ollama --version2. 使用ollama下载deepseek #不同的参数规格对硬件有不同的要…

【Kubernetes】常用命令全解析:从入门到实战(中)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是k8s 2、K8s的核心功能 二、资…

[ComfyUI]腾讯开源黑科技Sonic,插件更新,更加可控啦

一、Sonic更新介绍 大家还记得我前分享过腾讯开源的Sonic这个项目吧&#xff0c;通过照片声音就可以生成非常不错的数字人开口说话的视频。 当时我就挺满意的&#xff0c;不过那时候输出还只能输出正方形的视频&#xff0c;这点就让我留有遗憾。 今天我再去翻作者的项目官网…

设计模式Python版 命令模式(上)

文章目录 前言一、命令模式二、命令模式示例 前言 GOF设计模式分三大类&#xff1a; 创建型模式&#xff1a;关注对象的创建过程&#xff0c;包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。结构型模式&#xff1a;关注类和对象之间的组合&…