树的结构定义与存储方式:vector 数组及链式前向星
树作为非线性数据结构,具有递归定义特性。文章阐述了树的基本术语如度、高度及路径,区分了有序无序及有根无根树。重点讲解孩子表示法在树存储中的应用,对比了基于 vector 数组的动态存储与基于数组模拟链表的链式前向星实现。代码示例展示了如何在 C++ 中构建无向图形式的树结构,指出 vector 虽稍慢但通常足够使用,实际刷题可根据习惯选择。

树作为非线性数据结构,具有递归定义特性。文章阐述了树的基本术语如度、高度及路径,区分了有序无序及有根无根树。重点讲解孩子表示法在树存储中的应用,对比了基于 vector 数组的动态存储与基于数组模拟链表的链式前向星实现。代码示例展示了如何在 C++ 中构建无向图形式的树结构,指出 vector 虽稍慢但通常足够使用,实际刷题可根据习惯选择。

树型结构是一类重要的非线性数据结构。
注:这个认知主要会影响我们对于树的存储。在存储树结构的时候,最重要的就是要存下逻辑关系。如果是无根树,父子关系不明确,此时我们需要把所有的情况都存下来。如 a 和 b 之间有一条边,我们不仅要存 a 有一个孩子 b,也要存 b 有一个孩子 a。(有时有根树也需要这样存储)
树结构相对线性结构来说就比较复杂。存储时,既要保存值域,也要保存结点与结点之间的关系。实际中树有很多种存储方式:双亲表示法,孩子表示法、孩子双亲表示法以及孩子兄弟表示法等。现阶段,只要掌握孩子表示法,学会用孩子表示法存储树,并且在此基础上遍历整棵树。后续会在并查集中学习双亲表示法。至于其它存储形式,在学习算法阶段不要求掌握。
孩子表示法是将每个结点的孩子信息存储下来。 如果是在无根树中,父子关系不明确,我们会将与该结点相连的所有点都存储下来。
vector 是可变长数组,如果只涉及尾插,效率还是可以的。而树结构这种一对多的关系,正好可以利用尾插,把所有的关系全部存起来。
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e5 + 10;
vector<int> edges[N];
int main() {
int n;
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;
}
链式前向星的本质就是用数组来模拟链表。 本质:其实就是把 b 头插到 a 所在的链表后面。
#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;
}
关于 vector 数组以及链式前向星:

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online