树:倒过来的家族谱
把一棵树倒过来看:根在最上面,向下分叉长出子节点,每个节点又能再分叉。这就是数据结构里的"树",文件目录、网页 DOM、组织架构都是树。
二叉树是树的特殊形式:每个节点最多有两个孩子(左孩子、右孩子)。别小看这个限制,二叉树是竞赛和面试里出现频率最高的树结构。
树是最"自然"的数据结构,因为世界本来就是分层组织的。
本文核心知识点
- 节点树的组成单位。
- 递归处理树的天然工具。
- 遍历前中后三种顺序。
- 深度递归求高度的经典题。
二叉树的术语
几个必须记住的词:根节点(最顶上的)、左孩子/右孩子(每个节点的两个分支)、叶子(没有孩子的节点)、深度(根到某节点的层数)、子树(任一节点连同它下面的部分)。
理解"子树"特别重要:每个节点向下看,都是一棵完整的树——这就是递归能派上用场的原因。
用 Python 定义节点
定义节点只要三个字段:值、左孩子、右孩子。用类或字典都可以。
class Node:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
这段代码搭出了一棵四节点的树,画出来就是 1 下面挂着 2 和 3,2 下面挂着 4。
递归:自己调用自己
递归就是一个函数调用自己,但必须有两个要素:递归公式(怎么变小)和终止条件(什么时候停)。
求二叉树深度:一个节点的深度 = 1 + max(左子树深度, 右子树深度),空节点深度为 0。这既是递归公式,也是终止条件。
def depth(node):
if node is None:
return 0
return 1 + max(depth(node.left), depth(node.right))
三行代码,递归把整棵树的深度算出来了——这就是递归的威力。
前序、中序、后序遍历
遍历就是按顺序访问每个节点。按"根"的位置分三种:
- 前序:根 → 左 → 右。
- 中序:左 → 根 → 右。
- 后序:左 → 右 → 根。
def preorder(node):
if node is None:
return
print(node.val)
preorder(node.left)
preorder(node.right)
三种遍历的代码几乎一样,只是 print 的位置不同——理解这一点,遍历就全部拿下了。
求深度与叶子数
竞赛里最常见的两道递归题:求深度、数叶子。叶子是没有孩子的节点,判断条件是"左空且右空"。
def count_leaves(node):
if node is None:
return 0
if node.left is None and node.right is None:
return 1
return count_leaves(node.left) + count_leaves(node.right)
把这两道题背下来,再配合遍历练习,二叉树的递归手感就出来了。
树的应用与下一步
树的用处远超想象:二叉搜索树(BST)让查找变快、堆(完全二叉树)是优先队列的底子、表达式树解析数学公式、哈夫曼树做压缩。
下一步建议:先学二叉搜索树的插入和查找,再学堆;等递归熟了,再挑战平衡树。配合我们频道的"数据结构入门"和"贪心与 DP",竞赛基础就能打牢。
本节核心结论
- 递归两个要素:公式+终止。
- 遍历换 print 位置即可。
- BST/堆树的进阶方向。
- 练手深度、叶子、遍历。