醋醋百科网

Good Luck To You!

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

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

一、问题定义:什么是二叉树的深度?

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

举个简单例子:

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

二、核心解法:DFS与BFS的思路拆解

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

1. DFS解法:递归遍历,分治求深度

原理:“自下而上”的分治思想

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

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

形象类比

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

2. BFS解法:层次遍历,计数层数

原理:“自上而下”的逐层统计

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

  1. 边界处理:若根节点为null,直接返回深度0;
  2. 初始化队列:将根节点入队,并用depth变量记录深度(初始为0);
  3. 逐层遍历
  4. 记录当前队列的大小(即当前层的节点数);
  5. 遍历当前层的所有节点:弹出队首节点,若其有左/右子节点,将子节点入队;
  6. 每遍历完一层,depth加1;
  7. 返回结果:遍历结束后,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通过队列实现“层次遍历”,核心是“逐层统计,不遗漏任何一层”。

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

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言