程序员必学:二叉树面试通关宝典

二叉树

一、二叉树基础概念与分类

  1. 基本定义
    二叉树是每个节点最多有两个子节点的树结构,包含根节点、左子树、右子树。核心特性包括高度、深度、层级等。
  2. 常见分类
    • 满二叉树:所有非叶子节点均有2个子节点。
    • 完全二叉树:除最后一层外均为满结构,最后一层节点左对齐。
    • 二叉搜索树(BST):左子树所有节点值小于根节点,右子树所有节点值大于根节点。
    • 平衡二叉树(AVL树):任意节点左右子树高度差不超过1,优化查询效率。

二、核心操作与遍历算法

  1. 遍历方法

    遍历类型递归实现非递归实现(栈/队列)应用场景
    前序遍历根→左→右栈模拟复制二叉树结构
    中序遍历左→根→右栈模拟二叉搜索树升序输出
    后序遍历左→右→根栈模拟+反转计算子树节点数量
    层序遍历队列分层处理队列迭代求树宽度、锯齿形遍历

    示例代码(C++层序遍历递归解法):

    void levelOrder(TreeNode* root, int level, vector<vector<int>>& res) {
        if (!root) return;
        if (res.size() == level) res.push_back({});
        res[level].push_back(root->val);
        levelOrder(root->left, level + 1, res);
        levelOrder(root->right, level + 1, res);
    }
    
  2. 高频操作

    • 翻转二叉树:递归交换左右子树(LeetCode 226)。
    • 求最大深度:递归取左右子树深度最大值 +1(LeetCode 104)。
    • 求最小深度:需处理单子树为空的情况(LeetCode 111)。

三、高频面试题型与解析

  1. 基础性质判断

    • 相同树判断:递归比较根节点值及左右子树是否相同(LeetCode 100)。
    • 对称树判断:递归比较左右子树镜像,或队列迭代判断(LeetCode 101)。
  2. 结构操作类

    • 合并二叉树:递归叠加节点值,处理空子树情况(LeetCode 617)。
    • 二叉树展开为链表:前序遍历+修改指针(LeetCode 114)。
  3. 路径与序列问题

    • 路径总和:递归回溯判断路径和是否等于目标值(LeetCode 112)。
    • 二叉树的序列化:前序遍历生成字符串,反序列化时递归解析(LeetCode 297)。
  4. 高级应用

    • 最近公共祖先(LCA):后序遍历递归查找目标节点(LeetCode 236)。
    • 构建二叉树:根据前序+中序或中序+后序序列重建(LeetCode 105/106)。

四、二叉树变种与工程应用

  1. 二叉搜索树(BST)

    • 验证BST:中序遍历检查是否递增(LeetCode 98)。
    • BST插入/删除:保持有序性,删除时处理子节点替换。
  2. 平衡二叉树

    • AVL树旋转:通过左旋、右旋调整平衡因子。
    • 红黑树特性:近似平衡,广泛用于STL(如C++的map)。
  3. 堆结构

    • 完全二叉树实现:大根堆/小根堆用于优先队列、堆排序(LeetCode 215)。

五、学习建议与高频考点总结

  1. 刷题重点

    题型核心技巧相关题目
    遍历算法递归与非递归实现LeetCode 144/94/145/102
    子树判断递归匹配结构LeetCode 572
    路径问题回溯+剪枝LeetCode 113/124
    二叉树构建分治法处理序列LeetCode 105/106
  2. 注意事项

    • 边界条件:处理空树、单节点、不平衡树等场景。
    • 复杂度优化:递归可能导致栈溢出,需掌握迭代解法。
    • 工程应用:红黑树在数据库索引、语言标准库中的使用。

高频题

  1. 二叉树遍历(前序、中序、后序):递归法,前序(根-左-右),中序(左-根-右),后序(左-右-根)。
//前序
void preorder(TreeNode* root, vector<int>& res) {
    if (!root) return;
    res.push_back(root->val);     // 访问根节点 
    preorder(root->left, res);   // 递归左子树 
    preorder(root->right, res);  // 递归右子树 
}
//中序
void inorder(TreeNode* root, vector<int>& res) {
    if (!root) return;
    inorder(root->left, res);    // 递归左子树 
    res.push_back(root->val);     // 访问根节点 
    inorder(root->right, res);   // 递归右子树 
}
//后续
void postorder(TreeNode* root, vector<int>& res) {
    if (!root) return;
    postorder(root->left, res);   // 递归左子树 
    postorder(root->right, res);  // 递归右子树 
    res.push_back(root->val);      // 访问根节点 
}
  1. 层序遍历:即逐层的从左到后访问所有节点,用广度优先遍历 BFS,使用队列保存当前层节点,循环处理每个节点并记录值,同时将子节点入队。
#include <queue>
#include <vector>
 
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
 
vector<int> levelOrder(TreeNode* root) {
    vector<int> res;
    if (!root) return res;
    
    queue<TreeNode*> q;//创建队列
    q.push(root); //根节点压入队列

    //当队列不为空时,循环处理节点
    while (!q.empty())  {
        TreeNode* node = q.front(); //获取队列的前端节点,即当前层的节点
        q.pop(); //移除队列的前端的节点
        res.push_back(node->val); //节点值加到结果数组里
        if (node->left) q.push(node->left); //左子节点入队
        if (node->right) q.push(node->right); //右子节点入队
    }
    return res;
}
  1. 二叉树的最大深度:递归法,树的最大深度等于左右子树的最大深度加 1。
int maxDepth(TreeNode* root) {
    if (!root) return 0;  // 空树深度为0 
    int left = maxDepth(root->left);
    int right = maxDepth(root->right);
    return max(left, right) + 1;  // 取左右子树深度的较大者加1
}
  1. 二叉树最小深度:利用队列进行广度优先搜索,找到第一个叶子节点时候返回当前层级。(叶子节点是指没有子节点,即没有左子节点和右子节点。)
int minDepth(TreeNode* root) {
    if (!root) return 0;
    queue<TreeNode*> q;
    q.push(root); 
    int depth = 0;
    
    while (!q.empty())  {
        depth++;
        int size = q.size(); 
        for (int i = 0; i < size; i++) {
            TreeNode* node = q.front(); 
            q.pop(); 
            // 发现叶子节点立即返回 
            if (!node->left && !node->right) return depth;
            if (node->left) q.push(node->left); 
            if (node->right) q.push(node->right); 
        }
    }
    return depth;  // 保证语法完整性 
}
  1. 相同的树:递归法,即两个二叉树当前节点值相等,左右子树结构相同即为相同的树。
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
 
bool isSameTree(TreeNode* p, TreeNode* q) {
    // 两个节点均为空,视为相同 
    if (!p && !q) return true; 
    // 一个为空另一个非空,结构不同 
    if (!p || !q) return false; 
    // 节点值不同则直接返回false 
    if (p->val != q->val) return false; 
    // 递归检查左右子树 
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
  1. 对称二叉树:递归法,即左子树的左节点与右子树的右节点、左子树的右节点与右子树的左节点需同时满足对称条件。
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
 
bool isSymmetric(TreeNode* root) {
    if (!root) return true;
    return compare(root->left, root->right);
}
 
bool compare(TreeNode* left, TreeNode* right) {
    // 基例处理 
    if (!left && !right) return true;  // 均为空节点 
    if (!left || !right) return false; // 仅一个为空 
    if (left->val != right->val) return false; // 节点值不同 
    
    // 递归比较内外侧子树 
    bool outside = compare(left->left, right->right); // 外侧对称(左左 vs 右右)
    bool inside = compare(left->right, right->left);  // 内侧对称(左右 vs 右左)
    return outside && inside;
}
  1. 翻转二叉树:通过递归交换每个节点的左右子树,实现自顶向下的翻转。
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
 
TreeNode* invertTree(TreeNode* root) {
    if (!root) return nullptr;  // 递归终止条件 
    
    // 交换当前节点的左右子树 
    TreeNode* temp = root->left;
    root->left = root->right;
    root->right = temp;
    
    // 递归处理子节点 
    invertTree(root->left);
    invertTree(root->right);
    return root;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码流怪侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值