【每日算法】Day 4-3:二叉树专题从原理到实战----大厂常考题型全解析(C++实现)

深入掌握二叉树的核心概念!今日带你全面解析二叉树的存储结构、遍历算法与构建技巧,结合大厂高频真题案例,迅速提升数据结构实战能力。

一、二叉树核心概念

二叉树(Binary Tree)是一种每个节点最多有两个子节点的数据结构,其基本特点为:

  • 节点结构: 每个节点包含数据域以及指向左子树和右子树的指针
  • 存储方式: 链式存储(指针实现)或顺序存储(数组模拟完全二叉树)
  • 遍历方式: 前序、中序、后序(深度优先遍历) & 层序(广度优先遍历)

基本节点的C++定义:

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

二、算法原理与步骤分解

1. 二叉树遍历方法

二叉树的遍历是解决众多题目(例如路径问题、搜索问题)的基础。常见遍历方法包括:

  • 前序遍历: 根节点 → 左子树 → 右子树
  • 中序遍历: 左子树 → 根节点 → 右子树
  • 后序遍历: 左子树 → 右子树 → 根节点
  • 层序遍历: 逐层从上到下、从左到右依次访问
2. 遍历的递归实现(示例:中序遍历)

使用递归可快速实现深度优先遍历:

#include <iostream>
#include <vector>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

void inorderTraversal(TreeNode* root, vector<int>& res) {
    if (root == nullptr) return;
    inorderTraversal(root->left, res);    // 访问左子树
    res.push_back(root->val);             // 访问当前节点
    inorderTraversal(root->right, res);   // 访问右子树
}

// 测试用例
int main() {
    /*
            1
           / \
          2   3
         / \
        4   5
    */
    TreeNode *root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);

    vector<int> result;
    inorderTraversal(root, result);
    cout << "中序遍历结果:";
    for (int num : result)
        cout << num << " ";
    return 0;
}
3. 层序遍历(广度优先搜索)

层序遍历通常借助队列,适用于搜索最短路径、判断二叉树完全性等场景:

#include <iostream>
#include <queue>
#include <vector>
using namespace std;

void levelOrderTraversal(TreeNode* root, vector<vector<int>>& res) {
    if (!root) return;
    queue<TreeNode*> q;
    q.push(root);
    while (!q.empty()) {
        int levelSize = q.size();
        vector<int> level;
        while (levelSize--) {
            TreeNode* node = q.front();
            q.pop();
            level.push_back(node->val);
            if (node->left) q.push(node->left);
            if (node->right) q.push(node->right);
        }
        res.push_back(level);
    }
}

// 测试层序遍历
int main() {
    /*
            1
           / \
          2   3
         / \
        4   5
    */
    TreeNode *root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);

    vector<vector<int>> levels;
    levelOrderTraversal(root, levels);
    
    cout << "层序遍历结果:" << endl;
    for (auto level : levels) {
        for (int num : level)
            cout << num << " ";
        cout << endl;
    }
    return 0;
}

三、完整二叉树算法实现(C++)

1. 构建二叉树:通过前序和中序遍历重构二叉树

不少厂商真题涉及从遍历序列构造树的问题。下面给出具体实现:

#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

TreeNode* buildTreeHelper(vector<int>& preorder, int preStart, int preEnd, 
                            vector<int>& inorder, int inStart, int inEnd, 
                            unordered_map<int, int>& inMap) {
    if (preStart > preEnd || inStart > inEnd)
        return nullptr;
    
    int rootVal = preorder[preStart];
    TreeNode* root = new TreeNode(rootVal);
    
    int inRoot = inMap[rootVal];
    int numsLeft = inRoot - inStart;
    
    root->left = buildTreeHelper(preorder, preStart + 1, preStart + numsLeft, 
                                 inorder, inStart, inRoot - 1, inMap);
    root->right = buildTreeHelper(preorder, preStart + numsLeft + 1, preEnd, 
                                  inorder, inRoot + 1, inEnd, inMap);
    
    return root;
}

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    unordered_map<int, int> inMap;
    for (int i = 0; i < inorder.size(); i++)
        inMap[inorder[i]] = i;
    return buildTreeHelper(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1, inMap);
}

// 测试用例
int main(){
    vector<int> preorder = {3,9,20,15,7};
    vector<int> inorder = {9,3,15,20,7};
    
    TreeNode* root = buildTree(preorder, inorder);
    // 此处可以调用前序、中序或层序遍历检测构建结果
    cout << "二叉树重构成功!" << endl;
    return 0;
}
2. 执行过程示例

以前序遍历序列 [3, 9, 20, 15, 7] 与中序遍历序列 [9, 3, 15, 20, 7] 为例:

  • 构树步骤:
    • 根节点确定为 3
    • 在中序序列中查找 3,将序列分割为左子树 [9] 和右子树 [15,20,7]
    • 递归构建左右子树,直至恢复完整的树结构

四、复杂度与优化

步骤时间复杂度空间复杂度优化方向
遍历(DFS/层序)O(n)递归时 O(h) 或队列 O(n)非递归实现减少递归深度风险
构建二叉树O(n)O(n)(辅助存储中序索引)利用哈希表降低查找中序下标时间复杂度

注意: 树的遍历大部分都需要访问所有节点,时间复杂度保持在线性级别。


五、大厂真题实战

真题1:二叉树的最近公共祖先(LeetCode 236)

题目描述:
给定一个二叉树,找到两个指定节点的最近公共祖先

参考解法:

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    if (root == nullptr || root == p || root == q) return root;
    
    TreeNode* left = lowestCommonAncestor(root->left, p, q);
    TreeNode* right = lowestCommonAncestor(root->right, p, q);
    
    if (left && right) return root;
    return left ? left : right;
}

真题2:二叉树的层序遍历(LeetCode 102)

题目描述:
返回二叉树的层序遍历结果,每层节点从左到右依次输出

参考解法:
前文已提供基于队列的层序遍历实现,详见上文层序遍历示例。


六、常见误区与避坑指南

  • 递归出口遗漏: 二叉树遍历与构建时,务必检查空节点条件
  • 遍历顺序混淆: 记住前序、中序与后序的递归调用顺序,避免顺序错误
  • 内存管理: 手动管理动态分配的节点,防止内存泄漏(使用智能指针可降低风险)
  • 索引计算错误: 在利用数组构建完全二叉树时,注意左右子节点的下标计算公式(左:2i+1,右:2i+2)

七、总结与扩展

核心优势:

  • 二叉树遍历和构建是解决树形结构问题的重要基础
  • 多种遍历方式适用于不同场景,递归与迭代各有优势
  • 利用哈希表辅助可优化构树与查找效率

扩展思考:

  • 如何高效完成二叉搜索树的平衡(如 AVL、红黑树)?
  • 二叉树如何应用在区间查询、优先级调度或 Huffman 编码等场景?
  • 如何用非递归方法实现后序遍历,避免递归带来的栈溢出风险?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值