数据结构中的树
与数组、链表这些线性的数据结构不同,树是**非线性**的,它天然带有层级关系。掌握树的关键在于跨越一个思维障碍:**习惯递归思维**。
#status / growing
#type / concept
#resource / algorithm
#ds / tree
[!info] related notes 算法面试题型 MOC 二叉树基础 DFS / BFS / 回溯
数据结构中的树
阶段一:建立直观认识与基础概念
不要一开始就钻进代码里,先在纸上画图,理解树的物理形态和专业术语。
你可以把树想象成一个倒置的现实中的树,或者文件系统的目录结构。
- 核心术语:
- 根节点 (Root):最顶端的节点。
- 叶子节点 (Leaf):没有子节点的节点(最底层的节点)。
- 父/子/兄弟节点:节点间的相对关系。
- 深度 (Depth):从根节点到某节点的路径长度。
- 高度 (Height):从某节点到最深叶子节点的路径长度。
阶段二:攻克核心骨架——二叉树 (Binary Tree)
二叉树是所有复杂树形结构的基础。每个节点最多有两个子节点(左子节点和右子节点)。
1. 理解树的代码表示
在代码中,一个树节点通常包含三个部分:数据、指向左子节点的指针、指向右子节点的指针。
2. 核心难点:二叉树的遍历 (Traversal)
这是重中之重。你需要彻底理解如何把一个二维的树结构,变成一维的访问序列。
- 深度优先搜索 (DFS) - 依赖栈 (Stack) 或递归:
- 前序遍历 (Pre-order):根 -> 左 -> 右
- 中序遍历 (In-order):左 -> 根 -> 右
- 后序遍历 (Post-order):左 -> 右 -> 根
- 广度优先搜索 (BFS) - 依赖队列 (Queue):
- 层序遍历 (Level-order):一层一层地从左到右访问。
想系统整理二叉树术语 + 四种遍历模板:见 二叉树基础。
学习技巧:初学遍历时,强烈建议手动在纸上画出递归的调用栈 (Call Stack)。理解了递归是如何“递”进去,又是如何“归”回来的,树的许多算法题就迎刃而解了。
阶段三:理解“秩序”——二叉搜索树 (Binary Search Tree, BST)
掌握了普通的二叉树,接下来要给它加上“规则”。BST 的规则很简单:
左子树上所有节点的值 < 根节点的值 < 右子树上所有节点的值。
- 为什么需要 BST? 为了快速查找。在理想情况下,BST 的查找、插入、删除的时间复杂度都是 $O(\log n)$,这比普通链表的 $O(n)$ 要快得多。
- 特性关联:对 BST 进行中序遍历,得到的一定是一个递增的有序序列。
阶段四:进阶与现实世界的应用 (高级树)
当你理解了 BST 及其在极端情况下可能退化成链表(时间复杂度跌落回 $O(n)$)的缺陷后,就可以了解那些更高级的树了。对于这些高级树,初期只需理解其设计原理和应用场景,不必死磕手写完整代码。
- 平衡二叉树 (AVL / 红黑树):通过旋转操作保持树的高度平衡,确保性能稳定在 $O(\log n)$。很多语言内部的 Map/Set 底层就是红黑树。
- 堆 (Heap):一种特殊的完全二叉树,用于实现优先队列。常用于解决 Top-K 问题。
- 字典树 (Trie):前缀树,极其适合用于搜索提示(Auto-complete)或路由前缀匹配。
- B树 / B+树:为了减少磁盘 I/O 而设计的“矮胖”树,是传统关系型数据库(如 MySQL)索引的基石。
阶段五:实践与沉淀
- 刻意练习:在 LeetCode 上按标签刷题。从“二叉树的最大深度”、“翻转二叉树”这些简单题开始,找找递归的感觉。
- 融入项目:既然你正在维护
DailyUse这样的 Monorepo 项目,不妨在里面单独建一个packages/data-structures模块,用你熟悉的语言自己把二叉树、BST 和各种遍历方法封装一遍。 - 知识卡片:将树的每个概念拆解成原子笔记(Atomic Notes),沉淀到你的 Obsidian 知识库里。比如,单独写一篇《为什么递归是解决树形结构的银弹?》。
你想先从最基础的二叉树代码定义和遍历开始看起,还是想了解一下树结构在前端/全栈开发中的实际应用场景?