在数据结构与算法领域,二叉树是高频考察的基础结构,而“求二叉树深度”更是入门级经典问题。它不仅能帮助我们理解二叉树的遍历逻辑,还能直观区分深度优先搜索(DFS)与广度优先搜索(BFS)两种核心算法思想。本文将从问题定义出发,拆解两种解法的原理,提供可直接运行的多语言代码,并通过实例验证效果,帮助初学者快速掌握。
一、问题定义:什么是二叉树的深度?
根据《剑指Offer》中的题目描述:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
举个简单例子:
- 若二叉树只有根节点,深度为1;
- 若根节点有一个左子节点,左子节点又有一个左子节点(共3层),深度为3;
- 若根节点同时有左、右子树,左子树深度为2,右子树深度为3,则整棵树的深度取最大值3。
二、核心解法:DFS与BFS的思路拆解
求解二叉树深度的本质,是找到“根节点到最远叶子节点的路径长度”。基于这个目标,我们有两种截然不同但同样高效的思路:递归式的DFS(深度优先)和迭代式的BFS(广度优先)。
1. DFS解法:递归遍历,分治求深度
原理:“自下而上”的分治思想
DFS的核心是“先深入子树,再回溯计算”,具体逻辑可拆解为3步:
- 终止条件:若当前节点为null(空树或叶子节点的子节点),深度为0(因为空节点不占层数);
- 递归分解:分别计算当前节点的左子树深度left和右子树深度right;
- 合并结果:当前节点的深度 = 左/右子树的最大深度 + 1(“+1”是因为要包含当前节点本身)。
形象类比
把二叉树想象成一棵“家谱树”:要知道爷爷的“辈分深度”,需要先知道爸爸和叔叔的辈分深度,取其中最大的那个加1(爷爷比爸爸高一辈);而爸爸的辈分深度,又需要先知道孙子的……直到找到“没有后代”的人(叶子节点),再一步步回溯计算。
2. BFS解法:层次遍历,计数层数
原理:“自上而下”的逐层统计
BFS的核心是“按层遍历节点,每遍历完一层,深度加1”,需要借助队列(先进先出)实现,具体逻辑拆解为4步:
- 边界处理:若根节点为null,直接返回深度0;
- 初始化队列:将根节点入队,并用depth变量记录深度(初始为0);
- 逐层遍历:
- 记录当前队列的大小(即当前层的节点数);
- 遍历当前层的所有节点:弹出队首节点,若其有左/右子节点,将子节点入队;
- 每遍历完一层,depth加1;
- 返回结果:遍历结束后,depth即为二叉树的深度。
形象类比
把二叉树想象成“多层楼房”:BFS就像“逐层查房”——先查1楼(根节点),记录层数1;再查2楼(根节点的子节点),记录层数2;直到查完最高层,此时的层数就是楼房的总高度(树的深度)。
三、实战代码:多语言实现与解析
1. 数据结构定义
无论哪种解法,首先需要定义二叉树的节点结构(以C++和Python为例):
// C++节点定义
struct TreeNode {
int val; // 节点值
TreeNode *left; // 左子节点指针
TreeNode *right; // 右子节点指针
// 构造函数:初始化节点值,左/右子节点默认为空
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
# Python节点定义
class TreeNode:
def __init__(self, x):
self.val = x # 节点值
self.left = None # 左子节点引用
self.right = None # 右子节点引用
2. DFS解法代码(C++/Python)
C++实现
class Solution {
public:
int TreeDepth(TreeNode* pRoot) {
// 终止条件:空节点深度为0
if (pRoot == NULL) {
return 0;
}
// 递归计算左、右子树深度
int leftDepth = TreeDepth(pRoot->left);
int rightDepth = TreeDepth(pRoot->right);
// 当前节点深度 = 最大子树深度 + 1
return (leftDepth > rightDepth) ? (leftDepth + 1) : (rightDepth + 1);
}
};
Python实现
class Solution:
def TreeDepth(self, root):
# 终止条件:空节点深度为0
if root is None:
return 0
# 递归计算左、右子树深度
left_depth = self.TreeDepth(root.left)
right_depth = self.TreeDepth(root.right)
# 当前节点深度 = 最大子树深度 + 1
return max(left_depth, right_depth) + 1
3. BFS解法代码(C++/Python)
C++实现(借助queue容器)
#include <queue> // 需包含队列头文件
using namespace std;
class Solution {
public:
int TreeDepth(TreeNode* pRoot) {
// 边界处理:空树深度为0
if (pRoot == NULL) {
return 0;
}
queue<TreeNode*> node_queue; // 存储待遍历的节点
node_queue.push(pRoot); // 根节点入队
int depth = 0; // 初始化深度为0
while (!node_queue.empty()) {
int level_size = node_queue.size(); // 当前层的节点数
depth++; // 遍历当前层前,深度先加1(因为当前层存在节点)
// 遍历当前层的所有节点
for (int i = 0; i < level_size; i++) {
TreeNode* current = node_queue.front(); // 取队首节点
node_queue.pop(); // 弹出队首节点
// 左子节点入队(若存在)
if (current->left != NULL) {
node_queue.push(current->left);
}
// 右子节点入队(若存在)
if (current->right != NULL) {
node_queue.push(current->right);
}
}
}
return depth;
}
};
Python实现(借助deque双端队列)
Python的list实现队列效率较低,推荐使用collections.deque(弹出队首元素时间复杂度为O(1)):
from collections import deque
class Solution:
def TreeDepth(self, root):
# 边界处理:空树深度为0
if root is None:
return 0
node_queue = deque() # 初始化队列
node_queue.append(root) # 根节点入队
depth = 0
while node_queue:
level_size = len(node_queue) # 当前层的节点数
depth += 1 # 遍历当前层,深度加1
# 遍历当前层的所有节点
for _ in range(level_size):
current = node_queue.popleft() # 弹出队首节点
# 左子节点入队
if current.left:
node_queue.append(current.left)
# 右子节点入队
if current.right:
node_queue.append(current.right)
return depth
四、实例验证:代码运行效果
为了验证代码正确性,我们构建一个具体的二叉树(如图所示),并通过测试用例运行:
1(根节点)
/ \
2 3
/ \
4 5
/
6(叶子节点)
Python测试代码
if __name__ == "__main__":
# 构建二叉树
A1 = TreeNode(1) # 根节点
A2 = TreeNode(2)
A3 = TreeNode(3)
A4 = TreeNode(4)
A5 = TreeNode(5)
A6 = TreeNode(6)
# 连接节点
A1.left = A2
A1.right = A3
A2.left = A4
A2.right = A5
A4.left = A6
# 测试DFS解法
dfs_solution = Solution()
dfs_result = dfs_solution.TreeDepth(A1)
print("DFS解法:二叉树深度 =", dfs_result) # 输出:4
# 测试BFS解法
bfs_solution = Solution()
bfs_result = bfs_solution.TreeDepth(A1)
print("BFS解法:二叉树深度 =", bfs_result) # 输出:4
结果分析
该二叉树的最长路径为“1→2→4→6”,共4个节点,因此深度为4。两种解法均正确返回结果,验证了代码的有效性。
五、两种解法的对比与选择
维度 DFS(递归) BFS(层次遍历) 实现复杂度 代码简洁,递归逻辑直观 需手动维护队列,代码稍长 时间复杂度 O(n)(每个节点遍历1次) O(n)(每个节点遍历1次) 空间复杂度 O(h)(h为树的深度,递归栈) O(w)(w为树的最大宽度,队列) 适用场景 树深度较小,避免栈溢出 树深度较大(如斜树),防止递归栈溢出
- 选择建议:
若二叉树为“平衡树”(深度较小),优先用DFS(代码简洁);
若二叉树为“斜树”(如所有节点只有左子树,深度接近n),递归可能导致栈溢出,此时优先用BFS。
六、总结
求二叉树深度是理解DFS和BFS的“入门钥匙”:
- DFS通过递归实现“分治思想”,核心是“先深入子树,再回溯合并结果”;
- BFS通过队列实现“层次遍历”,核心是“逐层统计,不遗漏任何一层”。
掌握这两种解法后,不仅能解决“二叉树深度”问题,还能迁移到“二叉树的最小深度”“判断平衡二叉树”等进阶问题中。建议初学者手动敲写代码,通过修改测试用例(如空树、单节点树、斜树)加深理解,为后续复杂算法打下基础。