Appearance
Tree / Binary Tree
目标:掌握秋招高频的二叉树结构、DFS/BFS、递归、BST 与完全二叉树;理解与 Stack / Queue / Heap 的联系,不扩展到低收益的高级树结构细节。
1. Binary Tree
二叉树要求:
每个节点最多有两个子节点。
普通二叉树不要求:
text
left < root < right该顺序约束属于 Binary Search Tree(BST)。
Python 节点结构:
python
class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None与链表的结构联系:
text
Linked List Node
= value + next
Binary Tree Node
= value + left + right最重要的递归结构:
text
Tree
= Root
+ Left Subtree
+ Right Subtree因此树天然适合递归处理。
2. DFS 与三种遍历
统一 DFS 框架:
python
def dfs(node):
if node is None:
return
# 前序位置
dfs(node.left)
# 中序位置
dfs(node.right)
# 后序位置对应:
text
Preorder: Root → Left → Right
Inorder: Left → Root → Right
Postorder: Left → Right → Root核心理解:
三种遍历本质上是同一个 DFS,只是处理当前节点的时机不同。
前序示例:
python
def preorder(node):
if node is None:
return
print(node.val)
preorder(node.left)
preorder(node.right)后序常见于“父节点答案依赖子树答案”的问题。
3. Recursive DFS vs Iterative DFS
递归 DFS:
系统通过 Call Stack 保存尚未执行完成的函数调用与返回位置。
Stack 是 LIFO,因此:
text
调用:A → B → D
返回:D → B → A迭代 DFS 可以显式维护 Stack。
前序遍历:
python
def preorder_iterative(root):
if root is None:
return
stack = [root]
while stack:
node = stack.pop()
print(node.val)
if node.right:
stack.append(node.right)
if node.left:
stack.append(node.left)如果希望先访问左子树,由于 Stack 是 LIFO,应:
text
先压 right
再压 left这样 left 会先被 pop。
注意:
text
DFS
= 搜索策略
递归 / Stack
= 实现方式4. DFS Complexity
若树有 n 个节点,每个节点访问一次:
text
Time: O(n)递归调用栈深度取决于树高 h:
text
Space: O(h)平衡树:
text
h ≈ O(log n)退化树:
text
h = O(n)所以不能看到两个递归调用就机械把复杂度相乘。
5. BFS / Level Order
BFS 按层访问:
text
第 1 层 → 第 2 层 → 第 3 层 → ...使用 Queue,因为需要 FIFO:
text
DFS → Stack
BFS → QueuePython 常用:
python
from collections import deque基本 BFS:
python
from collections import deque
def bfs(root):
if root is None:
return
queue = deque([root])
while queue:
node = queue.popleft()
print(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)按层处理:
python
queue = deque([root])
while queue:
level_size = len(queue)
for _ in range(level_size):
node = queue.popleft()
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)level_size 必须在当前层开始时固定,以区分当前层与处理过程中加入的下一层节点。
6. Maximum Depth
递归关系:
text
depth(root)
= max(depth(root.left), depth(root.right)) + 1空树:
text
0只有根节点:
text
1代码:
python
def max_depth(root):
if root is None:
return 0
left_depth = max_depth(root.left)
right_depth = max_depth(root.right)
return max(left_depth, right_depth) + 1这是典型后序思想:
text
孩子结果 → 父节点结果需要区分两个原因:
text
算法依赖关系:
父节点答案依赖左右子树答案
实现机制:
递归调用由 LIFO Call Stack 管理“必须先算子树”根本原因是数据依赖,不是因为 Stack 本身是 LIFO。
BFS 也可以通过统计层数求最大深度。
7. Binary Search Tree (BST)
对任意节点:
text
左子树所有值 < 当前节点 < 右子树所有值约束作用于整棵左右子树,而不只是直接孩子。
因此判断 BST 时,不能只比较父节点与直接孩子。
BST 查找:
text
target < node → left
target > node → right只需沿一条路径,因此:
text
Time = O(h)平衡时:
text
O(log n)退化为链表时:
text
O(n)BST 中序遍历得到有序序列,因为:
text
BST: Left < Root < Right
Inorder: Left → Root → Right8. BST vs Hash Table
text
Hash Table
→ 精确 key 查询平均 O(1)
→ 不擅长维护顺序和范围关系
BST
→ 查询 O(h),平衡时约 O(log n)
→ 保留有序结构
→ 更适合顺序 / 范围类操作例如:
text
查某个 key 是否存在
→ Hash 很强
查 20~50 范围、最小值、按序遍历
→ 有序 Tree 更自然9. Perfect / Complete / Balanced Binary Tree
Perfect Binary Tree
每一层全部填满。
若根节点为第 1 层,高度为 h:
text
n = 2^h - 1Complete Binary Tree
要求:
- 除最后一层外,其余层全部填满;
- 最后一层允许不满;
- 最后一层节点必须从左到右连续排列,不能跳位置。
若用数组从下标 0 开始存储,节点 i:
text
left = 2i + 1
right = 2i + 2
parent = (i - 1) // 2因为层序节点连续占据数组下标,父子关系可以直接由下标推导,所以无需为每个节点保存 left/right 指针。
这直接连接 Heap。
Balanced Binary Tree
平衡关注的是左右子树高度不要长期严重失衡,不要求节点全部填满。
严重退化:
text
A
\
B
\
C
\
D此时树的高度接近 n,BST 查询也会退化到 O(n)。
AVL Tree / Red-Black Tree 都属于用于控制 BST 退化的自平衡树;当前秋招阶段只要求理解这一作用,不展开旋转和详细性质。
10. Core Connections
text
Binary Tree
│
├── DFS
│ ├── Recursive → Call Stack
│ └── Iterative → Explicit Stack
│
├── BFS / Level Order
│ └── Queue
│
├── BST
│ └── Ordering / Search / Range
│
└── Complete Binary Tree
└── Compact Array Representation
└── HeapReview Focus
后续需要通过真实代码题继续强化:
- DFS 递归返回过程;
- 前中后序代码快速写出;
- BFS 层序与
level_size; - 最大深度;
- BST 整棵子树约束;
- 图中的 DFS/BFS 复用。
Practice:
04_Practice/CS_MCQs/Data_Structure_Lesson_2.md
Mistakes:
05_Mistakes/CS.md
Interview QA:
06_Interview/CS_QA/Data_Structure.md