news 2026/5/10 15:55:02

从零开始刷算法——二叉树篇:层序遍历 + 有序数组转二叉搜索树

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零开始刷算法——二叉树篇:层序遍历 + 有序数组转二叉搜索树

在二叉树的算法体系中,"读取"(遍历)与"写入"(构建)是两个最核心的命题。

本文将通过两道经典题目——二叉树的层序遍历有序数组转搜索树,深入剖析两种截然不同的思维模式:基于队列的迭代(BFS)基于递归的分治(Divide & Conquer),并从内存与指针的角度分析其底层实现。


一、 读取的艺术:二叉树的层序遍历

二叉树的层序遍历(Level Order Traversal)本质上是图论中的广度优先搜索(BFS)。不同于前中后序遍历“一条道走到黑”的深度优先逻辑,层序遍历要求我们按照“剥洋葱”的方式,一层一层地访问节点。

1. 核心代码实现

C++代码实现:

class Solution { // 思路: 先加入root进q,然后每次处理完front()之后把它左右子树加入进去,最重要的其实还是要记录当前的size,来记录有几个数进入vals作为一组 public: vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> ans; if (root == nullptr) return ans; queue<TreeNode*> q; q.push(root); while (!q.empty()) { vector<int> vals; // 快照,核心逻辑:固定住当前层的 size for (int i = q.size(); i > 0; --i) { vals.push_back(q.front()->val); if (q.front()->left) q.push(q.front()->left); if (q.front()->right) q.push(q.front()->right); q.pop(); // 要不就提前用node记录下来front要不就最后pop } ans.push_back(vals); } return ans; } };

2. 深度解析:队列与快照机制

很多初学者容易写成普通的 BFS,却无法将结果按层分开。上述代码中最精髓的一行在于:

for (int i = q.size(); i > 0; --i)

这里隐藏了一个**“快照”**思想:

  1. 锁定状态:在进入for循环之前,q.size()代表了当前这一层所有的节点数量。我们必须在循环开始前就确定循环次数。

  2. 动态入队:在循环内部,我们不断地push下一层的节点(左右孩子)。

  3. 时空隔离:如果不固定i的次数,而是每次判断q.size(),那么新加入的下一层节点会和当前层混在一起,导致分层逻辑失效。

通过这个机制,队列q充当了一个缓冲区,完美地衔接了上一层的消耗和下一层的生产。

3. 时空复杂度分析

  • 时间复杂度:O(N)

    • 每个节点进队一次、出队一次,操作次数与节点总数 N 成正比。

  • 空间复杂度:O(W)

    • W 为二叉树的最大宽度。

    • 在最坏情况下(满二叉树的最底层),队列中需要同时存储大约 N/2 个节点,因此空间复杂度与宽度相关,数量级上视为 O(N)。


二、 构建的艺术:有序数组转二叉搜索树

如果说层序遍历是利用队列进行“横向扫描”,那么构建平衡二叉搜索树(BST)则是利用递归进行“纵向切分”。

题目要求构建高度平衡的 BST,且输入数组是有序的。这天然符合二分法分治思想

1. 核心代码实现

C++代码实现:

class Solution { // 思路: 题目要求平衡也就是左右高度差为1以内, 那肯定要涉及到中间点, 利用二分的思想构造子树, dfs递归构造, 因为是左小右大, 所以构造左边从mid左边选,右边从mid右边选 TreeNode* dfs(vector<int>& nums, int left, int right) { if (left > right) return nullptr; int mid = left + (right - left) / 2; TreeNode* root = new TreeNode(nums[mid]); root->left = dfs(nums, left, mid - 1); root->right = dfs(nums, mid + 1, right); return root; } public: TreeNode* sortedArrayToBST(vector<int>& nums) { return dfs(nums, 0, nums.size() - 1); } };

2. 深度解析:堆内存与指针构建

在这段简短的递归代码中,TreeNode* root = new TreeNode(nums[mid]);这行代码极其关键,它揭示了 C++ 中二叉树构建的内存模型:

  1. 堆区(Heap)分配

    • 使用了new关键字。这意味着节点对象是创建在堆内存中的。

    • 这一点至关重要。如果是栈上分配(例如TreeNode node;),函数dfs一结束,节点就会被销毁。而堆上分配的节点生命周期独立于函数调用,保证了整棵树在递归结束后依然存在。

  2. 栈区(Stack)链接

    • dfs函数的每一次调用都在系统栈中开辟了一个栈帧。

    • 变量root是一个指针,暂存在栈上。

    • root->left = dfs(...)这一步,实际上是利用栈上的递归回溯,将分散在堆内存中的各个节点,通过指针像“锁链”一样串联起来,形成了树的结构。

这种**“取中点 -> 建根 -> 递归构建左右”的顺序,本质上是二叉树的前序遍历**逻辑。

3. 时空复杂度分析

  • 时间复杂度:O(N)

    • 每个数组元素只会被访问一次用来创建一个节点,不存在重复计算。

  • 空间复杂度:O(log N)

    • 这里的空间消耗主要来自递归调用栈

    • 由于我们每次都取中间点(mid),保证了生成的树是高度平衡的。

    • 平衡二叉树的高度是log N,因此递归的最大深度也就是log N

    • 注:这里未计算存储结果所需的 O(N) 空间,仅计算算法辅助空间。


三、 总结

这两道题目展示了二叉树算法的两种极端:

  1. 层序遍历

    • 数据结构:队列 (Queue)

    • 特性:FIFO (先进先出)

    • 思维:迭代,水平扩展,通过 size控制层级。

  2. 平衡构建

    • 数据结构:系统栈 (System Stack / Recursion)

    • 特性:LIFO (后进先出)

    • 思维:递归,深度优先,通过二分保证平衡。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 6:01:10

【TSP问题】基于变邻域搜索算法求解旅行社问题附Matlab代码和论文

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1…

作者头像 李华
网站建设 2026/5/3 5:49:39

碳排放压力之下,企业用能管理正在悄悄换一种玩法

安科瑞刘鸿鹏摘要在“双碳”目标和制造业成本压力持续加大的背景下&#xff0c;企业用能管理正从“统计型管理”向“过程型、决策型管理”转变。传统依赖人工抄表和经验判断的能源管理模式&#xff0c;已难以支撑企业对能效提升、用能安全与碳资产管理的综合需求。本文结合企业…

作者头像 李华
网站建设 2026/5/9 3:18:31

学Java后端必须学spring,spring框架为什么这么多人用?

Spring是我们Java程序员面试和工作都绕不开的重难点。很多粉丝就经常跟我反馈说由Spring衍生出来的一系列框架太多了&#xff0c;根本不知道从何下手&#xff1b;大家学习过程中大都不成体系&#xff0c;但面试的时候都上升到源码级别了&#xff0c;你不光要清楚了解Spring源码…

作者头像 李华
网站建设 2026/5/3 3:40:11

对接API获取马来西亚历史数据

通过API获取马来西亚股票市场的历史数据是许多开发者和分析师的常见需求。下面我将为您梳理基于API的完整对接方案。对接API获取马来西亚历史数据 &#x1f511; 准备工作 开始调用接口前&#xff0c;API文档的API密钥&#xff08;API Key&#xff09; &#xff0c;这是所有请…

作者头像 李华
网站建设 2026/5/3 7:27:57

互联网大厂Java面试实战:Spring Boot、微服务与AI技术全解析

互联网大厂Java面试实战&#xff1a;Spring Boot、微服务与AI技术全解析 在互联网大厂Java求职面试中&#xff0c;技术深度和业务场景的结合尤为重要。本文通过模拟一场严肃的面试官与搞笑水货程序员谢飞机的面试对话&#xff0c;涵盖了核心Java、Spring生态、微服务架构、数据…

作者头像 李华