程序设计 树基础
✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。
🍎个人主页:小嗷犬的个人主页
🍊个人网站:小嗷犬的技术小站
🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。
本文目录
- 引入
- 定义
- 有关树的定义
- 适用于无根树和有根树
- 只适用于有根树
- 特殊的树
- 存储
- 只记录父结点
- 邻接表
- 左孩子右兄弟表示法
- 过程
- 实现
- 二叉树
- 树的遍历
- 树上 DFS
- 二叉树上 DFS
- 前序遍历
- 中序遍历
- 后序遍历
- 反推
- 树上 BFS
- 无根树
- 过程
- 实现
- 有根树
引入
图论中的树和现实生活中的树长得一样,只不过我们习惯于处理问题的时候把树根放到上方来考虑。
这种数据结构看起来像是一个倒挂的树,因此得名。
定义
一个没有固定根结点的树称为 无根树(unrooted tree)。无根树有几种等价的形式化定义:
- 有 n n n 个结点, n − 1 n-1 n−1 条边的连通无向图
- 无向无环的连通图
- 任意两个结点之间有且仅有一条简单路径的无向图
- 任何边均为桥的连通图
- 没有圈,且在任意不同两点间添加一条边之后所得图含唯一的一个圈的图
在无根树的基础上,指定一个结点称为 根,则形成一棵 有根树(rooted tree)。有根树在很多时候仍以无向图表示,只是规定了结点之间的上下级关系,详见下文。
有关树的定义
适用于无根树和有根树
- 森林(forest):每个连通分量(连通块)都是树的图。按照定义,一棵树也是森林。
- 生成树(spanning tree):一个连通无向图的生成子图,同时要求是树。也即在图的边集中选择 n − 1 n - 1 n−1 条,将所有顶点连通。
- 无根树的叶结点(leaf node):度数不超过 1 1 1 的结点。
- 有根树的叶结点(leaf node):没有子结点的结点。
只适用于有根树
-
父亲(parent node):对于除根以外的每个结点,定义为从该结点到根路径上的第二个结点。 根结点没有父结点。
-
祖先(ancestor):一个结点到根结点的路径上,除了它本身外的结点。 根结点的祖先集合为空。
-
子结点(child node):如果 u u u 是 v v v 的父亲,那么 v v v 是 u u u 的子结点。
子结点的顺序一般不加以区分,二叉树是一个例外。 -
结点的深度(depth):到根结点的路径上的边数。
-
树的高度(height):所有结点的深度的最大值。
-
兄弟(sibling):同一个父亲的多个子结点互为兄弟。
-
后代(descendant):子结点和子结点的后代。
或者理解成:如果 u u u 是 v v v 的祖先,那么 v v v 是 u u u 的后代。

-
子树(subtree):删掉与父亲相连的边后,该结点所在的子图。

特殊的树
-
链(chain/path graph):满足与任一结点相连的边不超过 2 2 2 条的树称为链。
-
菊花/星星(star):满足存在 u u u 使得所有除 u u u 以外结点均与 u u u 相连的树称为菊花。
-
有根二叉树(rooted binary tree):每个结点最多只有两个儿子(子结点)的有根树称为二叉树。常常对两个子结点的顺序加以区分,分别称之为左子结点和右子结点。
大多数情况下,二叉树 一词均指有根二叉树。 -
完整二叉树(full/proper binary tree):每个结点的子结点数量均为 0 0 0 或者 2 2 2 的二叉树。换言之,每个结点或者是树叶,或者左右子树均非空。

-
完全二叉树(complete binary tree):只有最下面两层结点的度数可以小于 2 2 2,且最下面一层的结点都集中在该层最左边的连续位置上。

-
完美二叉树(perfect binary tree):所有叶结点的深度均相同的二叉树称为完美二叉树。

Proper binary tree 的汉译名称不固定,且完全二叉树和满二叉树的定义在不同教材中定义不同,遇到的时候需根据上下文加以判断。
ACMer 所说的「满二叉树」多指完美二叉树。
存储
只记录父结点
用一个数组 parent[N] 记录每个结点的父亲结点。
这种方式可以获得的信息较少,不便于进行自顶向下的遍历。常用于自底向上的递推问题中。
邻接表
-
对于无根树:为每个结点开辟一个线性列表,记录所有与之相连的结点。
std::vector<int> adj[N]; -
对于有根树:
-
方法一:若给定的是无向图,则仍可以上述形式存储。下文将介绍如何区分结点的上下关系。
-
方法二:若输入数据能够确保结点的上下关系,则可以利用这个信息。为每个结点开辟一个线性列表,记录其所有子结点;若有需要,还可在另一个数组中记录其父结点。
std::vector<int> children[N]; int parent[N];当然也可以用其他方式(如链表)替代
std::vector。
-
左孩子右兄弟表示法
过程
对于有根树,存在一种简单的表示方法。
首先,给每个结点的所有子结点任意确定一个顺序。
此后为每个结点记录两个值:其 第一个子结点 child[u] 和其 下一个兄弟结点 sib[u]。若没有子结点,则 child[u] 为空;若该结点是其父结点的最后一个子结点,则 sib[u] 为空。
实现
遍历一个结点的所有子结点可由如下方式实现。
int v = child[u]; // 从第一个子结点开始
while (v != EMPTY_NODE)
{// ...// 处理子结点 v// ...v = sib[v]; // 转至下一个子结点,即 v 的一个兄弟
}
也可简写为以下形式。
for (int v = child[u]; v != EMPTY_NODE; v = sib[v])
{// ...// 处理子结点 v// ...
}
二叉树
需要记录每个结点的左右子结点。
int parent[N];
int lch[N], rch[N];
// -- or --
int child[N][2];
树的遍历
树上 DFS
在树上 DFS 是这样的一个过程:先访问根节点,然后分别访问根节点每个儿子的子树。
可以用来求出每个节点的深度、父亲等信息。
二叉树上 DFS
前序遍历

按照 根,左,右 的顺序遍历二叉树。
void preTrav(BiTree *root)
{if (root){cout << root->key << " ";preTrav(root->left);preTrav(root->right);}
}
中序遍历

按照 左,根,右 的顺序遍历二叉树。
void midTrav(BiTree *root)
{if (root){midTrav(root->left);cout << root->key << " ";midTrav(root->right);}
}
后序遍历

按照 左,右,根 的顺序遍历二叉树。
void lastTrav(BiTree *root)
{if (root){lastTrav(root->left);lastTrav(root->right);cout << root->key << " ";}
}
反推
已知中序遍历序列和另外一个序列可以求第三个序列。

- 前序的第一个是 root,后序的最后一个是 root。
- 先确定根节点,然后根据中序遍历,在根左边的为左子树,根右边的为右子树。
- 对于每一个子树可以看成一个全新的树,仍然遵循上面的规律。
树上 BFS
从树根开始,严格按照层次来访问节点。
BFS 过程中也可以顺便求出各个节点的深度和父亲节点。
无根树
过程
树的遍历一般为深度优先遍历,这个过程中最需要注意的是避免重复访问结点。
由于树是无环图,因此只需记录当前结点是由哪个结点访问而来,此后进入除该结点外的所有相邻结点,即可避免重复访问。
实现
void dfs(int u, int from)
{// 递归进入除了 from 之外的所有子结点// 对于出发结点,from 为空,故会访问所有相邻结点,这与期望一致for (int v : adj[u])if (v != from)dfs(v, u);
}// 开始遍历时
int EMPTY_NODE = -1; // 一个不存在的编号
int root = 0; // 任取一个结点作为出发点
dfs(root, EMPTY_NODE);
有根树
对于有根树,需要区分结点的上下关系。
考察上面的遍历过程,若从根开始遍历,则访问到一个结点时 from 的值,就是其父结点的编号。
通过这个方式,可以对于无向的输入求出所有结点的父结点,以及子结点列表。
相关文章:
程序设计 树基础
✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。 🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心&…...
Java 并发编程与CAS基本原理
一、Java并发基础知识 Java里的程序天生就是多线程的,那么有几种新启线程的方式? 两种,启动线程的方式只有: 1、X extends Thread;,然后X.start; 2、X implements Runnable;然后交给Thread运行。 Java…...
qt creater运行按钮灰色,问题记录
第一次安装还没运行就出了三个错误: 1.F:\wei\Qt\Tools\CMake_64\share\cmake-3.24\Modules\CMakeTestCXXCompiler.cmake:62: error: The C compiler "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/BIN/amd64/cl.exe" is not able to compil…...
【jvm】类加载器的分类
目录 一、说明二、示例2.1 代码2.2 截图 三、启动类加载器四、扩展类加载器五、应用程序类加载器 一、说明 1.jvm支持两种类型的类加载器,分别是引导类加载器(bootstrap classloader)和自定义类加载器(user-defined classloader&a…...
电路基础之电容
电容器(Capacitor)是由两个导体电极之间夹着一个电介质而组成的元件。这两个电极可以是金属板、箔片、涂层等,而电介质则是放置在电极之间的绝缘材料。电容器的基本构成包括以下几个要素: 电极:电容器的电极是两个导体…...
函数柯里化
文章目录 基本概念柯里化(Currying)是什么?通用的柯里化实现ES5 实现ES6 实现 基本概念 在讲柯里化之前我们先来了解一些基本概念: Function.length: length 属性指明函数的形参个数 function func1() {} function …...
【HBZ分享】ES中的Reindex重建索引
Reindex如何实现索引重建? 滚动索引 批量复制 Reindex存在的问题 如果新的索引没有提前创建好,并指定字段类型,那么重建后的新索引类型极有可能会和旧的索引不一致,因为ES他会推断类型,而推断错误率从实战来说那是…...
【PostgreSQL】几个提高性能的小特性
一、LOCALE 与 “operator class” 在PostgreSQL里,LOCALE默认使用C的本地化规则。LOCALE是一种文化偏好的区域设置,包括字母表、排序、数字格式等。 LOCALE里有一个比较重要的规则LC_COLLATE,即排序方式(Collation),它会对数据…...
[C语言] 指针
1. 指针是什么 2. 指针和指针类型 3. 野指针 4. 指针运算 5. 指针和数组 6. 二级指针 7. 指针数组 目录 1. 指针是什么? 2. 指针和指针类型 2.1 指针-整数 2.2 指针的解引用 3. 野指针 3.1 野指针成因 3.2 如何规避野指针 4. 指针运算 4.1 指针…...
win10在vmware15中安装macos10.13系统
第一步、安装vmware版本信息如下 第二步、下载unlocker-main和darwin.iso放到安装文件夹 第三步、管理员身份运行win-install.cmd 第四步、运行vmware新建虚拟机 第五步、启动新创建的虚拟机macOS 10.13并选择语言 第六步、选择磁盘工具抹掉磁盘 第七步、格式化完成后退出磁盘工…...
Node.js:实现遍历文件夹下所有文件
Node.js:实现遍历文件夹 代码如下 const fs require(fs) const path require(path)function traverseFolder(folderPath) {// 读取文件夹列表const files fs.readdirSync(folderPath)// 遍历文件夹列表files.forEach(function (fileName) {// 拼接当前文件路径…...
Git详解及使用
Git简介 Git 是一种分布式版本控制系统,它可以不受网络连接的限制,加上其它众多优点,目前已经成为程序开发人员做项目版本管理时的首选,非开发人员也可以用 Git 来做自己的文档版本管理工具。 大概是大二的时候开始接触和使用Gi…...
Jmeter设置中文的两种方式,建议使用第二种
方案一 进入jmeter图像化界面,选择Options下的Choose Language,再选择Chinese(Simplified)。这个就是选择语言为简体中文(缺陷:这个只是在本次使用时为中文,下次打开默认还是英文的) 方案二(…...
【ARM 嵌入式 编译系列 7.1 -- GCC 链接脚本中节区及各个段的详细介绍】
文章目录 什么是Section(节区)输入文件常见节区有哪些?什么是 glue code?.glue_7和.glue_7的作用是什么?链接脚本中的 KEEP 关键字是什么呢作用?链接脚本中的 PROVIDE 关键字是什么呢作用? 上篇文章:ARM 嵌…...
一文读懂HTML
文章目录 HTML的历史HTML的作用HTML的基本语言 HTML的历史 HTML(HyperText Markup Language)的历史可以追溯到20世纪90年代早期,它是互联网发展的重要里程碑之一。以下是HTML的历史概述: 早期阶段(1980年代末 - 1990年…...
MOCK测试
介绍 mock:就是对于一些难以构造的对象,使用虚拟的技术来实现测试的过程。 mock测试:在测试过程中,对于某些不容易构造或者不容易获取的对象,可以用一个虚拟的对象来代替的测试方 法。 接口Mock测试:在接口…...
Flutter源码分析笔记:Widget类源码分析
Flutter源码分析笔记 Widget类源码分析 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132259681 【介绍】&#x…...
PyTorch 微调终极指南:第 2 部分 — 提高模型准确性
一、说明 如今,在训练深度学习模型时,通过在自己的数据上微调预训练模型来迁移学习已成为首选方法。通过微调这些模型,我们可以利用他们的专业知识并使其适应我们的特定任务,从而节省宝贵的时间和计算资源。本文分为四个部分&…...
MySQL数据库----------安装anaconda---------python与数据库的链接
作者前言 🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂 🎂 作者介绍: 🎂🎂 🎂 🎉🎉🎉…...
nuxt页面布局
nuxt页面默认布局文件在layouts目录下default.vue,可将页面的头部和脚部提取出来,形成布局页,将主内容区域的内容替换成<nuxt />。附default.vue代码: <template><div class"app-container"><div…...
编程未来发展趋势
编程未来发展趋势:技术变革与无限可能 在数字化浪潮席卷全球的今天,编程作为技术发展的核心驱动力,正以前所未有的速度重塑世界。从人工智能的崛起到量子计算的突破,编程的未来充满无限可能。本文将探讨编程领域的三大发展趋势&a…...
三星990 evo plus 这个产品厉害吗
三星 990 EVO Plus 是一款定位精准、技术很有特点的“次旗舰”级 PCIe 4.0 固态硬盘。 它不属于追求极致性能的 990 PRO 系列,而是面向主流用户群体。它的“厉害”之处不在于绝对的跑分,而在于它在性能、能效、温控和价格之间找到了一个很好的平衡点&am…...
微信QQ防撤回补丁终极指南:一键解决消息被撤回的烦恼
微信QQ防撤回补丁终极指南:一键解决消息被撤回的烦恼 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: https://gitcode.com…...
别被“纯解释型语言”骗了:揭开 Python 运行机制的真实底牌
在编程语言的鄙视链中,Python 经常被贴上一个标签:“它只是一门解释型语言,所以它很慢。” 这种刻板印象往往来自于我们在命令行里敲下 python script.py 后它立即运行的爽快感。没有漫长的 make,没有 gcc 编译报错,仿…...
鸿蒙4.0和Android 12上,为什么你的App拿不到真实蓝牙MAC地址了?一个老需求的适配踩坑记
鸿蒙4.0与Android 12蓝牙权限适配实战:从虚拟地址到设备绑定的完整解决方案 当智能家居App弹出"设备绑定失败"提示时,作为开发者的你是否意识到这背后隐藏着从Android 10到鸿蒙4.0长达四年的隐私保护演进史?本文将带你穿越六个系统…...
Llama2跑不起来?别急,可能是flash-attn的ABI版本搞的鬼(CUDA 12.2 + PyTorch 2.1.2 实测避坑)
Llama2部署遇阻?深入解析flash-attn的ABI兼容陷阱 当你在本地部署Llama2等大语言模型时,是否遇到过这样的场景:按照官方文档一步步操作,flash-attn显示安装成功,却在import时遭遇莫名其妙的报错?这种"…...
彻底告别OpenClaw使用焦虑:我给他装上了“透视眼”和“批量克隆模组贾
指令替换 项目需求:将加法指令替换为减法 项目目录如下 /MyProject ├── CMakeLists.txt # CMake 配置文件 ├── build/ #构建目录 │ └── test.c #测试编译代码 └── mypass2.cpp # pass 项目代码 一,测试代码示例 test.c // test.c #includ…...
The Algorithms - PHP搜索算法详解:二分查找到插值搜索的完整教程
The Algorithms - PHP搜索算法详解:二分查找到插值搜索的完整教程 【免费下载链接】PHP All Algorithms implemented in PHP 项目地址: https://gitcode.com/gh_mirrors/php1/PHP 在编程世界中,搜索算法是处理数据查找的基础工具。PHP搜索算法不仅…...
跨模态检索技术全景:从核心方法到前沿应用与挑战
1. 跨模态检索技术演进脉络 跨模态检索技术的发展可以追溯到早期的统计学习方法。最初的研究主要依赖**典型相关分析(CCA)**这类线性方法,通过寻找不同模态数据之间的线性关系来实现对齐。比如在2000年代初,研究者们用CCA处理文本…...
FastECompass:嵌入式轻量级倾角补偿电子罗盘算法库
1. FastECompass 库概述FastECompass 是一个专为嵌入式系统设计的轻量级电子罗盘(e-compass)算法库,核心目标是在资源受限的微控制器上实时、高效地解算三维姿态角:俯仰角(Pitch)、横滚角(Roll&…...
