二叉树深度求解:从原理到实战(DFS与BFS双解法)

B站影视 内地电影 2025-08-26 21:33 3

摘要:在数据结构与算法领域,二叉树是高频考察的基础结构,而“求二叉树深度”更是入门级经典问题。它不仅能帮助我们理解二叉树的遍历逻辑,还能直观区分深度优先搜索(dfs)与广度优先搜索(BFS)两种核心算法思想。本文将从问题定义出发,拆解两种解法的原理,提供可直接运行的

在数据结构与算法领域,二叉树是高频考察的基础结构,而“求二叉树深度”更是入门级经典问题。它不仅能帮助我们理解二叉树的遍历逻辑,还能直观区分深度优先搜索(dfs)与广度优先搜索(BFS)两种核心算法思想。本文将从问题定义出发,拆解两种解法的原理,提供可直接运行的多语言代码,并通过实例验证效果,帮助初学者快速掌握。

根据《剑指Offer》中的题目描述:
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

举个简单例子:

若二叉树只有根节点,深度为1;若根节点有一个左子节点,左子节点又有一个左子节点(共3层),深度为3;若根节点同时有左、右子树,左子树深度为2,右子树深度为3,则整棵树的深度取最大值3。

求解二叉树深度的本质,是找到“根节点到最远叶子节点的路径长度”。基于这个目标,我们有两种截然不同但同样高效的思路:递归式的DFS(深度优先)和迭代式的BFS(广度优先)。

DFS的核心是“先深入子树,再回溯计算”,具体逻辑可拆解为3步:

终止条件:若当前节点为null(空树或叶子节点的子节点),深度为0(因为空节点不占层数);递归分解:分别计算当前节点的左子树深度left和右子树深度right;合并结果:当前节点的深度 = 左/右子树的最大深度 + 1(“+1”是因为要包含当前节点本身)。

把二叉树想象成一棵“家谱树”:要知道爷爷的“辈分深度”,需要先知道爸爸和叔叔的辈分深度,取其中最大的那个加1(爷爷比爸爸高一辈);而爸爸的辈分深度,又需要先知道孙子的……直到找到“没有后代”的人(叶子节点),再一步步回溯计算。

BFS的核心是“按层遍历节点,每遍历完一层,深度加1”,需要借助队列(先进先出)实现,具体逻辑拆解为4步:

边界处理:若根节点为null,直接返回深度0;初始化队列:将根节点入队,并用depth变量记录深度(初始为0);逐层遍历:记录当前队列的大小(即当前层的节点数);遍历当前层的所有节点:弹出队首节点,若其有左/右子节点,将子节点入队;每遍历完一层,depth加1;返回结果:遍历结束后,depth即为二叉树的深度。

把二叉树想象成“多层楼房”:BFS就像“逐层查房”——先查1楼(根节点),记录层数1;再查2楼(根节点的子节点),记录层数2;直到查完最高层,此时的层数就是楼房的总高度(树的深度)。

无论哪种解法,首先需要定义二叉树的节点结构(以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 # 右子节点引用class Solution {public:int TreeDepth(TreeNode* proot) {// 终止条件:空节点深度为0if (pRoot == NULL) {return 0;}// 递归计算左、右子树深度int leftDepth = TreeDepth(pRoot->left);int rightDepth = TreeDepth(pRoot->right);// 当前节点深度 = 最大子树深度 + 1return (leftDepth > rightDepth) ? (leftDepth + 1) : (rightDepth + 1);}};Python实现class Solution:def TreeDepth(self, root):# 终止条件:空节点深度为0if root is None:return 0# 递归计算左、右子树深度left_depth = self.TreeDepth(root.left)right_depth = self.TreeDepth(root.right)# 当前节点深度 = 最大子树深度 + 1return max(left_depth, right_depth) + 1#include // 需包含队列头文件using namespace std;class Solution {public:int TreeDepth(TreeNode* pRoot) {// 边界处理:空树深度为0if (pRoot == NULL) {return 0;}queue node_queue; // 存储待遍历的节点node_queue.push(pRoot); // 根节点入队int depth = 0; // 初始化深度为0while (!node_queue.empty) {int level_size = node_queue.size; // 当前层的节点数depth++; // 遍历当前层前,深度先加1(因为当前层存在节点)// 遍历当前层的所有节点for (int i = 0; i left != NULL) {node_queue.push(current->left);}// 右子节点入队(若存在)if (current->right != NULL) {node_queue.push(current->right);}}}return depth;}};

Python的list实现队列效率较低,推荐使用collections.deque(弹出队首元素时间复杂度为O(1)):

from collections import dequeclass Solution:def TreeDepth(self, root):# 边界处理:空树深度为0if root is None:return 0node_queue = deque # 初始化队列node_queue.append(root) # 根节点入队depth = 0while 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(叶子节点)if __name__ == "__main__":# 构建二叉树A1 = TreeNode(1) # 根节点A2 = TreeNode(2)A3 = TreeNode(3)A4 = TreeNode(4)A5 = TreeNode(5)A6 = TreeNode(6)# 连接节点A1.left = A2A1.right = A3A2.left = A4A2.right = A5A4.left = A6# 测试DFS解法dfs_solution = Solutiondfs_result = dfs_solution.TreeDepth(A1)print("DFS解法:二叉树深度 =", dfs_result) # 输出:4# 测试BFS解法bfs_solution = Solutionbfs_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通过队列实现“层次遍历”,核心是“逐层统计,不遗漏任何一层”。

掌握这两种解法后,不仅能解决“二叉树深度”问题,还能迁移到“二叉树的最小深度”“判断平衡二叉树”等进阶问题中。建议初学者手动敲写代码,通过修改测试用例(如空树、单节点树、斜树)加深理解,为后续复杂算法打下基础。

来源:码农世界

相关推荐