数据结构与算法入门:从树到二叉树,一文吃透核心概念
在编程世界里,数据结构是程序的骨架,而树形结构则是其中最常用、最优雅的一类。无论是文件系统、数据库索引,还是各种高级算法,树与二叉树都扮演着不可或缺的角色。本文将从零开始,带你系统理解树与二叉树的概念、结构、性质以及存储方式,并结合 Java、Go、C++、TypeScript、Python 等主流语言的实践视角,帮你打下扎实的数据结构基础。
树的概念与结构
树是一种非线性数据结构,由 n(n ≥ 0)个有限结点组成一个具有层次关系的集合。形象地说,它就像一棵倒挂的树——根朝上,叶朝下。在树结构中:
- 有一个特殊的结点称为根结点,它没有前驱结点。
- 除根结点外,其余结点被分成 M(M > 0)个互不相交的集合 T₁、T₂、…、Tₘ,每个集合又是一棵子树。
- 每棵子树的根结点有且只有一个前驱,可以有 0 个或多个后继。
- 树是递归定义的,子树之间不能有交集,否则就变成了图结构。




关键特性: 一棵 N 个结点的树有 N-1 条边;除了根结点,每个结点有且仅有一个父结点。子树之间不能相交,这是树与图的核心区别。
树的相关术语
掌握树的常用术语,是理解后续内容的基础。下面列出最核心的几个概念:
- 父结点/双亲结点: 若某结点含有子结点,则该结点称为其子结点的父结点。
- 子结点/孩子结点: 一个结点含有的子树的根结点称为该结点的子结点。
- 结点的度: 一个结点有几个孩子,它的度就是多少。
- 树的度: 一棵树中,最大的结点的度称为树的度。
- 叶子结点/终端结点: 度为 0 的结点称为叶结点。
- 分支结点/非终端结点: 度不为 0 的结点。
- 兄弟结点: 具有相同父结点的结点互称为兄弟结点。
- 结点的层次: 根为第 1 层,根的子结点为第 2 层,以此类推。
- 树的高度或深度: 树中结点的最大层次。
- 结点的祖先: 从根到该结点所经分支上的所有结点。
- 路径: 一条从树中任意节点出发,沿父节点-子节点连接,到达任意节点的序列。
- 子孙: 以某结点为根的子树中任一结点都称为该结点的子孙。
- 森林: 由 M(M > 0)棵互不相交的树的集合称为森林。

树的表示方法
由于树结构比线性表复杂得多,不仅要存储值域,还要存储结点之间的关系。实际应用中,常见的表示方式包括:双亲表示法、孩子表示法、孩子双亲表示法以及孩子兄弟表示法。其中,孩子兄弟表示法最为常用,它用两个指针分别指向第一个孩子和下一个兄弟,从而将多叉树转化为二叉树来存储。
struct TreeNode
{
struct Node* child; // 左边开始的第一个孩子结点
struct Node* brother; // 指向其右边的下一个兄弟结点
int data; // 结点中的数据域
};


⚠️ 在 Java、Go、C++ 等语言中,孩子兄弟表示法通常通过结构体或类来实现,每个结点包含数据域、firstChild 指针和 nextSibling 指针。这种表示方式不仅节省空间,而且便于递归遍历。
树形结构的实际应用场景
树形结构在现实世界中无处不在,最典型的例子就是文件系统。计算机通过树形结构来组织和管理文件和文件夹,每个文件夹可以包含子文件夹或文件,形成清晰的层级关系。此外,在 Web 开发中,DOM 树、路由树等都是树形结构的应用。


在 Python 和 TypeScript 中,树结构常用于实现 JSON 解析、AST(抽象语法树)等高级功能。掌握树的基本概念,对于理解这些复杂系统大有裨益。
二叉树的概念与结构
在树形结构中,二叉树 是最常用的一种。一棵二叉树是结点的一个有限集合,该集合由一个根结点加上两棵分别称为左子树和右子树的二叉树组成,或者为空。二叉树有以下特点:
- 二叉树不存在度大于 2 的结点。
- 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树。


现实世界中的二叉树例子也很常见,比如表达式树、决策树等。


特殊的二叉树
满二叉树
一个二叉树,如果每一层的结点数都达到最大值,则称为满二叉树。若层数为 K,则结点总数为 2^K - 1。

完全二叉树
完全二叉树 是由满二叉树引出的概念。对于深度为 K、有 n 个结点的二叉树,当且仅当其每一个结点都与深度为 K 的满二叉树中编号从 1 到 n 的结点一一对应时,称为完全二叉树。满二叉树是特殊的完全二叉树。

完全二叉树在堆排序和优先队列中应用广泛,Java 中的 PriorityQueue、C++ 中的 priority_queue 都基于完全二叉树实现。
二叉树的重要性质
掌握以下性质,可以帮助你更好地理解二叉树的行为:
- 若规定根结点的层数为 1,则一棵非空二叉树的第 i 层上最多有 2^(i-1) 个结点。
- 若规定根结点的层数为 1,则深度为 h 的二叉树的最大结点数是 2^h - 1。
- 具有 n 个结点的满二叉树的深度 h = log₂(n+1)。
这些性质在算法分析中经常用到,例如在 Go 或 Rust 中实现平衡树时,需要利用这些公式来保证树的高度可控。
二叉树的存储结构
二叉树一般可以使用两种结构存储:顺序结构 和 链式结构。
顺序结构
顺序结构使用数组来存储,一般只适合表示完全二叉树,因为非完全二叉树会造成空间浪费。完全二叉树更适合使用顺序结构存储。现实中,堆(一种二叉树)就使用顺序结构的数组来存储。


⚠️ 注意:数据结构中的堆与操作系统中的堆是两回事,前者是数据结构,后者是内存管理区域。
链式结构
链式存储结构使用链表来表示二叉树,每个结点由三个域组成:数据域、左指针域和右指针域。左右指针分别指向左孩子和右孩子。链式结构又分为二叉链和三叉链,当前学习中一般使用二叉链,而红黑树等高级数据结构会用到三叉链。


在 TypeScript 和 Python 中,链式二叉树通常用类或字典来实现,代码简洁且易于理解。例如,Python 中可以用嵌套字典表示二叉树结点,而 TypeScript 中可以用接口定义结点类型。
[AFFILIATE_SLOT_1]总结与展望
本文从树的基本概念出发,系统讲解了树的定义、术语、表示方法以及实际应用场景,并深入分析了二叉树的概念、特殊类型、重要性质和两种存储结构。树与二叉树是数据结构中的核心内容,也是后续学习堆、二叉搜索树、AVL 树、红黑树等高级结构的基础。无论你使用 Java、Go、C++ 还是 Python,掌握这些思想都将让你的编程能力更上一层楼。
[AFFILIATE_SLOT_2]建议: 学习完理论后,不妨动手用你熟悉的语言实现一棵二叉树,并尝试完成前序、中序、后序遍历。实践是检验真理的唯一标准!
浙公网安备 33010602011771号