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

数据结构进阶:树与递归之美

树是一个对于我这种小白来说是接触的第一个较复杂的数据结构,不像之前的线性结构,树让人感觉是从一个线到面的进阶。

树的定义是由一个根节点和许多子节点组成,再由子节点成为新的根节点有点像递归的过程,因此树的许多操作都要有递归的参与。

树的基本术语:

节点的度:树中的节点的子节点的个数称为度。

树的度:树中节点最大的度。

树的高度:树的层数或者深度。

路径:两个子结点之间的距离。

树又分为有根树和无根树,无序树指的是树的根是变化的根节点可以是子节点,子节点可以是根节点。有根树的根节点是固定的。树又分为有序树和无序树,有序树中树的子节点不可变化,无序树反之。

树的储存是一个相较于线性结构完全不同的,由于一对多的特性,使得他的存储变得困难。当我们在处理无根树时,由于根的不确定性,所以应在每个节点相互存储两次。对此我们有两种存储方式;vector数组和链式前向星。

vector数组是将以根节点为数组名的数组中存储他的子节点。

#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 u, v; cin >> u >> v; edges[u].push_back(v); edges[v].push_back(u);//由于没有固定的根节点,需要相互储存 } return 0; }

链式前向向星指的是用链表进行存储。

#include <iostream> using namespace std; const int N = 1e5 + 10; int h[N], e[2 * N], ne[2 * N]; int n, id; void add(int a, int b) { id++; e[id] = b; ne[id] = h[a]; h[a] = id; } int main() { cin >> n; for(int i; i < n; i++) { int a, b; cin >> a >> b; add(a,b); add(b,a);//要将两种根的情况存储 } return 0; }

树的遍历如果按照之前的方法随便遍历的话,很容易漏掉数据。因此树有它特有的两种遍历方式,深度优先遍历DFS和宽度优先遍历BFS。

深度优先遍历是由根节点为起点一直往子节点的子节点不断遍历,直到找到叶子节点(没有子节点)时,原路返回至其他子节点再进行遍历,直到将所有数据遍历完结束。

#include <iostream> #include <vector> using namespace std; const int N = 1e6 + 10; vector<int>edges[N]; int n; bool st[N];//由于根节点不知,要将历遍过的节点标记防止死循环 void dfs(int u)//以它为根节点的往后的子节点 { cout << u <<" "; st[u] = true; for(auto v : edges[u]) { if(!st[v]) { dfs(v); } } } int main() { int n; cin >> n; for(int i = 1; i < n; i++) { int u, v; cin >> u >> v; edges[u].push_back(v); edges[v].push_back(u); } dfs(1);//以1为根结点的树 }

上述使用的是vector数组储存的树的深度优先遍历,接下来使用链式前向星再来模拟一次。要点:由于根节点的未知,要使用额外的bool 数组来标记已历遍过的数据。

#include <iostream> using namespace std; const int N = 1e6 + 10; int h[N], e[N * 2], ne[N * 2]; int id, n; bool st[N]; void add(int a,int b) { id++; e[id] = b; ne[id] = h[a]; h[a] = id; } int dfs(int u) { cout << u <<" "; st[u] = true; for(int i = h[a]; i = ne[id]) { 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); }

现在介绍宽度优先遍历,也叫广度优先遍历,指的是将同一层的节点遍历完后再遍历下一层。所以根据队列的特性,我们可以应用queue来完成这个遍历。

我们还是先用vector数组的存储方法来模拟:(不要忘了将已遍历过了的点标记 ,与之前相同)

#include <iostream> #include <vector> #include <queue> using namespace std; const int N = 1e6 + 10; vector<int>edges[N]; int n; bool st[N]; void bfs() { queue<int>q; q.push(1); 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 u, v; edges[u].push_back(v); edges[v].push_back(u); } bfs(); }

再来使用链式前向星来储存时的bfs:

#include <iostream> #include <queue> using namespace std; const int N = 1e6 + 10; int h[N], e[N * 2], ne[N * 2]; int n, id; bool st[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); 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(); }#include <iostream> #include <queue> using namespace std; const int N = 1e6 + 10; int h[N], e[N * 2], ne[N * 2]; int n, id; bool st[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); 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(); }

树的种类还有许多可分为N叉树,我认为树的进阶和之后的节点的捆绑就是类似图的数据结构吧,当然纯属个人想法,等到学到该内容再与大家讨论。

http://www.jsqmd.com/news/85089/

相关文章:

  • 软件测试20个基础面试题【含答案】
  • 软件测试面试题含答案
  • NeurIPS 2025重磅突破:Tar-7B实现视觉理解与生成的统一范式
  • 1、商业模式:创新、数字化转型与数据分析的融合洞察
  • 2025软件测试面试题(持续更新)
  • 阶跃星辰开源语音大模型Step-Audio2mini震撼发布:重新定义端到端音频AI技术边界
  • 谷歌Gemma 3 270M开源:轻量级AI模型如何重塑移动端智能体验
  • 从“接口404”到“内存爆炸”——前端调试的Chrome实战指南
  • 智谱AI推出GLM-4.5V-FP8多模态模型,视觉语言理解能力刷新行业标杆
  • 百度ERNIE-4.5轻量化模型突破推理效率瓶颈:210亿参数实现128K上下文智能处理
  • 字节跳动Seed-OSS-36B震撼开源:512K超长上下文引领大模型效率革命
  • 【核心复现】模拟风电不确定性——拉丁超立方抽样生成及缩减场景研究(Matlab代码)
  • LightVAE:重塑视频生成效率标准,开创低显存高速度新范式
  • 【压缩空气储能】非补燃压缩空气储能系统集成的零碳排放综合能源优化调度(Matlab代码实现)
  • 突破AI记忆瓶颈:M3-Agent多模态智能体如何重塑长时序交互能力
  • 储能参与现货电能量-调频辅助服务市场的双层交易决策研究(Matlab代码实现)
  • PCB实战及拓展坞实现
  • 基于改进灰狼算法的并网交流微电网经济优化调度研究(Matlab代码实现)
  • 基于模型预测控制MPC的光伏供电的DC-AC变换器设计研究(Simulink仿真实现)
  • 基于自抗扰控制ADRC的永磁同步电机仿真模型(Simulink仿真实现)
  • 【太阳能学报EI复现】基于粒子群优化算法的风-水电联合优化运行分析(Matlab代码实现)
  • 华为部分机型Android渲染异常修复:保障用户视觉体验的技术攻坚
  • 开源里程碑:WebRL-Llama-3.1-8B让网页智能体效能提升8倍,开启自动化新纪元
  • MiniMax Agent:重构智能生产力边界,通用智能体60天内渗透50%团队协作场景
  • 在线课堂微信小程序毕设源码(源码+lw+部署文档+讲解等)
  • 英伟达Nemotron Nano v2横空出世:90亿参数模型改写小模型性能天花板,20万亿token预训练数据首次开源
  • Qwen3-VL-8B深度测评:解锁多模态模型在技术流程图解析中的实战价值
  • 9、自动存储管理(ASM)全面解析
  • 10、为 Oracle Database 10g RAC 安装 Linux 系统全攻略
  • 11、为 Oracle lOgRAC 安装配置和验证 Linux 系统全指南