算法练习-二叉树的层序遍历(思路+流程图+代码)

难度参考

难度:中等

分类:二叉树

难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。且所在课程未提供测试平台,故实现代码主要为自行测试的那种,以下内容均为个人笔记,旨在督促自己认真学习。

题目

给你二叉树的根节点root,返回其节点值的层序遍历。(即逐层地,从左到右访问所有节点)。

示例1:

输入:root=[3,9,20,null,null,15,7]

输出:[3],[9,20],[15,7]

提示:

树中节点数目在范围[0,20]内

-100<=Node.Val<=1000

思路

对于这个问题,我们可以使用广度优先搜索(BFS)算法来进行二叉树的层序遍历。BFS 通常使用队列来实现,通过不断出队和入队的方式,将每一层的节点依次遍历。

  1. 首先,我们需要定义一个队列(queue)来存储待遍历的节点。初始时,将根节点(root)入队。
  2. 然后,进入循环,直到队列为空。在每一次循环中,分别执行以下步骤:
    • 从队列中取出当前节点,并将当前节点的值存入结果数组中(该层的结果数组)。
    • 如果当前节点的左子节点不为空,将左子节点入队。
    • 如果当前节点的右子节点不为空,将右子节点入队。
  3. 循环结束后,我们就能得到一个每层节点值的层序遍历结果数组。

最后,根据题目的要求,返回层序遍历的结果数组。

示例

假设我们有以下的二叉树:

复制代码
     3
    / \
   9  20
     /  \
    15   7

我们可以按照层序遍历的顺序逐层访问节点。根据题目要求,层序遍历的结果数组应该是 [3], [9, 20], [15, 7]

  1. 首先,将根节点 3 入队。

    复制代码
         3                     --------------------
        / \                      3
       9  20                   --------------------        
         /  \
        15   7                 result = {}
  2. 开始循环,第一层级只有根节点 3,所以当前队列中只有根节点 3。将根节点 3 出队,并将其值 3 放入当前层级结果数组中。然后,检查节点 3 的左右子节点,发现都不为空,将根节点的左子节点 9 入队,右子节点 20 入队。

    复制代码
         3                     --------------------
        / \                      9, 20
       9  20                   --------------------        
         /  \
        15   7                 result = {3}
  3. 进入下一层级循环。此时,队列中有两个节点,分别是节点 9 和节点 20。将节点 9 出队,并将其值 9 放入当前层级结果数组中。然后,检查节点 9 的左右子节点,发现都为空,所以不需要入队。接着,将节点 20 出队,并将其值 20 放入当前层级结果数组中。然后,将节点 20 的左子节点 15 入队,右子节点 7 入队。

    复制代码
         3                     --------------------
        / \                      15, 7
       9  20                   --------------------        
         /  \
        15   7                 result = {3, 9, 20}
  4. 再次进入下一层级循环。此时,队列中有两个节点,分别是节点 15 和节点 7。将节点 15 出队,并将其值 15 放入当前层级结果数组中。然后,检查节点 15 的左右子节点,发现都为空,所以不需要入队。接着,将节点 7 出队,并将其值 7 放入当前层级结果数组中。然后,检查节点 7 的左右子节点,发现都为空,所以不需要入队。

    复制代码
         3                     --------------------
        / \                      
       9  20                   --------------------        
         /  \
        15   7                 result = {3, 9, 20, 15, 7}
  5. 循环结束,得到层序遍历的结果数组 [3], [9, 20], [15, 7]

梳理

对于二叉树的层序遍历,使用队列是因为队列的先进先出(FIFO)特性能够确保每一层的节点按照从左到右的顺序被访问

具体来说,层序遍历的思路是从根节点开始,依次将节点的左子节点和右子节点加入到队列中,然后从队列中取出节点进行访问。这样做可以保证每一层的节点按照从左到右的顺序进行访问,因为队列中先入队的节点会先出队。

通过使用队列,保证了层序遍历的节点访问顺序正确,能够按照层级逐步扩展,并且能够将每一层的节点按照顺序存储到结果数组中。

具体流程中,我们通过循环不断从队列中取出节点,并将其值存入结果数组中。然后,检查当前节点的左右子节点,如果存在则将其加入到队列中,以便后续的访问。

总结来说,队列在层序遍历中起到了承载节点的作用,能够确保每一层的节点按照顺序被访问。通过队列的先进先出特性,我们能够按照层级逐步扩展,从而得到二叉树的层序遍历结果。

代码

复制代码
#include <iostream> // 包含输入输出流库
#include <queue> // 包含队列库
#include <vector> // 包含向量库

using namespace std; // 使用标准命名空间

// 定义二叉树的节点
struct TreeNode {
    int val; // 节点值
    TreeNode* left; // 左子节点指针
    TreeNode* right; // 右子节点指针
    
    // 构造函数
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

// 层序遍历函数
vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> result; // 存放最终层序遍历结果的向量
    
    // 如果根节点为空,直接返回空结果
    if (root == nullptr) {
        return result;
    }
    
    // 创建队列,并将根节点入队
    queue<TreeNode*> q;
    q.push(root);
    
    // 循环遍历队列,直到队列为空
    while (!q.empty()) {
        // 获取当前层的节点数量
        int size = q.size();
        vector<int> levelNodes; // 存放当前层节点值的向量
        
        // 遍历当前层的节点
        for (int i = 0; i < size; i++) {
            // 弹出队列首节点,并将其值存入结果数组中
            TreeNode* node = q.front();
            q.pop();
            levelNodes.push_back(node->val);
            
            // 将当前节点的左子节点和右子节点入队
            if (node->left) {
                q.push(node->left);
            }
            
            if (node->right) {
                q.push(node->right);
            }
        }
        
        // 将当前层的节点值数组存入结果数组中
        result.push_back(levelNodes);
    }
    
    // 返回结果数组
    return result;
}

int main() {
    // 创建示例树 [3, 9, 20, null, null, 15, 7]
    TreeNode* root = new TreeNode(3);
    root->left = new TreeNode(9);
    root->right = new TreeNode(20);
    root->right->left = new TreeNode(15);
    root->right->right = new TreeNode(7);

    // 执行层序遍历
    vector<vector<int>> result = levelOrder(root);

    // 输出结果
    for (const auto& level : result) { // 遍历每一层
        cout << "["; // 给输出结果添加左括号
        for (const auto& val : level) { // 遍历当前层的节点值
            cout << val << ","; // 输出节点值和逗号
        }
        cout << "]"; // 给输出结果添加右括号
    }
    
    return 0;
}

时间复杂度:O(n)

空间复杂度:O(n)

  1. pop 是队列的操作,用于移除队列中的队头元素(第一个元素)。
  2. push 是队列的操作,用于将元素添加到队尾。
  3. push_back 是向量的操作,用于将元素添加到向量的末尾。

在代码中,首先创建一个空的队列 q,然后使用 q.push(root) 将根节点 root 添加到队列中。接下来,通过循环遍历队列,每次从队列中取出一个节点,并将其值添加到 levelNodes 向量中。

同时,如果节点有左子节点或右子节点,通过 q.push 将它们添加到队列的尾部,以便在后续循环中处理它们。

最后,将 levelNodes 添加到 result 向量中,表示当前层的节点值。

整个过程将重复直到队列为空。最后返回 result 向量,即为二叉树的层序遍历结果。

在主函数中,示例了如何使用 levelOrder 函数来执行对创建的二叉树进行层序遍历,并将结果输出到屏幕上。

打卡

相关推荐
雾里看山2 分钟前
算法思想之双指针(二)
算法·推荐算法
地平线开发者3 分钟前
征程 6|工具链 VP 示例中日志打印解读
算法·自动驾驶
飞川00111 分钟前
【LeetCode 热题100】146:LRU 缓存(详细解析)(Go语言版)
算法
uhakadotcom18 分钟前
Supervised Fine-Tuning(SFT)最佳实践
算法·面试·github
2301_794461571 小时前
详解七大排序
数据结构·算法·排序算法
爱coding的橙子1 小时前
蓝桥杯备赛 Day16 单调数据结构
数据结构·c++·算法·蓝桥杯
wuqingshun3141592 小时前
经典算法 约数之和
数据结构·c++·算法·蓝桥杯
溟洵2 小时前
【C/C++算法】蓝桥杯之递归算法(如何编写想出递归写法)
c语言·c++·算法
XYY3692 小时前
搜索与图论 树的深度优先遍历 树的重心
算法
破东风2 小时前
leetcode每日一题:替换子串得到平衡字符串
算法·leetcode·滑动窗口