跳到主要内容

二叉树

知识点概述​

二叉树是每个节点最多有两个子节点的树结构,是最常见的树形结构。

二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构。二叉树的分支具有左右次序,不能随意颠倒。

节点定义​

class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

二叉树类型​

1. 满二叉树​

每层节点都达到最大值,深度为 k 的满二叉树有 2^k - 1 个节点。

除最后一层节点外,其他所有节点都有两个子结点,必定是完全二叉树。

2. 完全二叉树​

除最后一层外,若其余层都是满的,并且最后一层是满的或者是在右边缺少连续若干节点,则这个二叉树就是完全二叉树。

简单来说:除最后一层外,其他层的节点数都达到最大,最后一层的节点都靠左排列(或满的)。

当根节点的值为 1 的情况下,若父结点的序号是 i,那么左子节点的序号就是 2i,右子节点的序号是 2i+1。这个性质使得完全二叉树利用数组存储时可以极大地节省空间,以及利用序号找到某个节点的父结点和子节点。

完全二叉树示例图1.webp

完全二叉树的顺序存储示例图.webp

3. 二叉搜索树(BST)​

  • 左子树所有节点值 < 根节点值
  • 右子树所有节点值 > 根节点值
  • 左右子树也都是 BST

4. 平衡二叉树​

任意节点的左右子树高度差不超过 1。

包括AVL树和红黑树。

常见操作​

遍历模板​

参考 树 的遍历方法。

层序遍历(BFS)​

from collections import deque

def levelOrder(root):
if not root:
return []

result = []
queue = deque([root])

while queue:
level_size = len(queue)
current_level = []

for _ in range(level_size):
node = queue.popleft()
current_level.append(node.val)

if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)

result.append(current_level)

return result

常见题型​

1. 递归遍历​

  • 前序、中序、后序遍历
  • 树的深度和高度

2. 层序遍历​

  • BFS 遍历
  • 右视图
  • 之字形遍历

相关题目:

  • 二叉树的层序遍历
  • 二叉树的右视图
  • 二叉树的锯齿形层序遍历

3. 路径问题​

  • 路径和
  • 最长路径
  • 路径是否存在

4. 构造与修改​

  • 翻转二叉树
  • 从遍历序列构造
  • 合并二叉树

解题技巧​

技巧 1:递归模板​

def traverse(root):
# 1. 终止条件
if not root:
return

# 2. 处理当前节点(前序位置)
process(root)

# 3. 递归左子树
traverse(root.left)

# 4. 处理当前节点(中序位置)
process(root)

# 5. 递归右子树
traverse(root.right)

# 6. 处理当前节点(后序位置)
process(root)

技巧 2:层序遍历模板​

使用队列,记录每层大小。

技巧 3:路径问题​

使用回溯 + DFS。

DFS 的两种思路​

自顶向下 DFS(先序遍历)​

在「递」的过程中维护值,从根节点向下传递信息。

# 判断是否存在根到叶的路径和为 targetSum(自顶向下:沿路径累减目标值)
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
# 叶子节点:判断当前累计值是否正好匹配
if not root.left and not root.right:
return root.val == targetSum
# 向下传递 targetSum - root.val(自顶向下传递信息)
return (self.hasPathSum(root.left, targetSum - root.val) or
self.hasPathSum(root.right, targetSum - root.val))

自底向上 DFS(后序遍历)​

在「归」的过程中计算,先递归处理子节点,再处理当前节点。

# 求二叉树最大深度(自底向上:先求左右子树深度,再合并 +1)
# 注意用 max 而非 +:+ 会把左右子树深度相加,得到的是"路径节点总数"
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1

# 合并二叉树
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
if root1 is None:
return root2
if root2 is None:
return root1
return TreeNode(
root1.val + root2.val,
self.mergeTrees(root1.left, root2.left),
self.mergeTrees(root1.right, root2.right)
)

二叉搜索树(BST)​

性质​

  • 节点的左子树仅包含键小于节点键的节点
  • 节点的右子树仅包含键大于节点键的节点
  • 左右子树也必须是二叉搜索树

平衡的二叉搜索树插入、查找的时间复杂度都是 O(logn)

常见考点​

  • 中序遍历有序性
  • 插入与删除
  • 验证与构建

验证 BST​

def isValidBST(self, root: Optional[TreeNode], left=float('-inf'), right=float('inf')) -> bool:
if root is None:
return True
x = root.val
return left < x < right and \
self.isValidBST(root.left, left, x) and \
self.isValidBST(root.right, x, right)

BST 转累加树​

遍历顺序:右 → 根 → 左(降序遍历)

def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
s = 0
def dfs(node: TreeNode) -> None:
if node is None:
return
dfs(node.right) # 先遍历右子树
nonlocal s
s += node.val
node.val = s
dfs(node.left)
dfs(root)
return root

有序数组转平衡 BST​

关键:BST 中序遍历后变成升序数组!

def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
def dfs(left, right):
if left > right:
return None
mid = left + (right - left) // 2
root = TreeNode(nums[mid])
root.left = dfs(left, mid - 1)
root.right = dfs(mid + 1, right)
return root
return dfs(0, len(nums) - 1)

二叉树与链表​

二叉树展开为链表​

def flatten(self, root: TreeNode) -> None:
"""将二叉树原地展开为链表(Morris 风格,O(1) 额外空间)
核心:每遇到有左子树的节点,把当前右子树接到左子树的最右节点下"""
curr = root
while curr:
if curr.left:
# 找到左子树的最右节点(左子树中最后一个被访问的节点)
predecessor = curr.left
while predecessor.right:
predecessor = predecessor.right
# 将右子树接到左子树最右节点的右侧
predecessor.right = curr.right
# 左子树整体移到右边,置空左指针
curr.right = curr.left
curr.left = None
curr = curr.right

相关知识点​

题目列表​

简单:

  • 二叉树的前序遍历 / 中序遍历 / 后序遍历
  • 二叉树的最大深度
  • 翻转二叉树

中等:

  • 验证二叉搜索树
  • 二叉树的最近公共祖先
  • 从前序与中序遍历序列构造二叉树

困难:

  • 二叉树中的最大路径和
  • 二叉树的序列化与反序列化

重点提示​

  • 理解递归的本质:处理当前节点 + 递归子问题
  • 区分前中后序的处理时机
  • 层序遍历一定用 BFS(队列)
  • 深度优先用 DFS(递归或栈)

算法可视化​

下面的播放器可以改输入后重跑:把数组换成你自己的, 逐步看每一帧的状态怎么变。三种遍历只差「访问根」的位置。空槽位用虚线小点画出来 —— 它们是「这里没有孩子」,不是「这里看不见」。

算法可视化 · 树的 DFS 遍历(前序 / 中序 / 后序)可改输入后重跑
加载评论中...