剑指Offer:[第6天 搜索与回溯算法(简单)]--->从上到下打印二叉树Ⅱ

本文主要介绍了如何实现二叉树的层序遍历,即从上到下按层打印节点,同层节点从左到右排列。通过使用广度优先搜索(BFS)策略,利用队列进行节点的存储和出队,从而达到按层打印的效果。在代码实现中,首先处理了树为空的情况,然后初始化二维数组和队列,接着进行BFS循环,每次循环处理当前层的节点并将其子节点入队。最后返回二维数组结果。该算法的时间复杂度和空间复杂度均为O(N),其中N为树的节点数量。
摘要由CSDN通过智能技术生成


一、题目描述

从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

例如:
给定二叉树[3,9,20,null,null,15,7]

    3
   / \
  9  20
    /  \
   15   7

返回:

[
  [3],
  [9,20],
  [15,7]
]

提示:
节点总数<=1000


二、思路分析

注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献

思路

①按层打印:题目要求的二叉树的层序遍历又称为二叉树的广度优先搜索(BFS)。BFS通常借助队列的先入先出特性来实现。
②每层打印到一行:将本层全部结点打印到一行,并将下一层全部结点加入队列,以此类推,即可分为多行打印。
算法流程:
1、特例处理:当根结点为空,则返回空列表[]
2、初始化:定义用于返回的二维数组res,定义队列queue,将根结点入队
3、BFS循环:当队列queue为空时跳出;
----3.1 计算出队列的长度,也就是当前层的结点数。
----3.2 当前层打印循环,循环次数为当前层结点数
------3.2.1 出队:队首元素出队,记为tmp
------3.2.2 打印:将tmp.val添加至res对应的地方
------3.2.3 添加子节点:若tmp的左(右)子结点不为空,则将左(右)子结点加入队列queue
4、返回值:返回二维数组res即可。
复杂度分析:
时间复杂度 O ( N ) \rm{O(N)} O(N)N为二叉树的结点数量,即BFS需循环N次。
空间复杂度 O ( N ) \rm{O(N)} O(N): 最差情况下,即当树为平衡二叉树时,最多有N/2个树结点同时在queue中,使用O(N)大小的额外空间。


三、整体代码

整体代码如下

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */

int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes) {
    //树为空时
    if (!root) {
        *returnSize = 0;
        *returnColumnSizes = NULL;
        return NULL;
    }
    *returnSize = 0;                                         //返回数组的行数,即二叉树的高度
    int** res = (int**)malloc(sizeof(int*) * 10001);         //返回数组
    *returnColumnSizes = (int*)malloc(sizeof(int) * 10001);  //返回数组中每一行的列数
    struct TreeNode** queue = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 10001);  //新建队列
    int head = -1;  //head为队首下标,初始化为-1,代表没有元素
    int rear = 0;   //rear为队尾元素后面的位置,初始化为0,代表需要入的元素插入到这个地方 
    queue[++head] = root;  //将根结点插入,队首坐标往后挪
    rear++;                //队尾位置往后挪
    //遍历二叉树
    while (head < rear) {
        /*
        记录当前的rear,因为我们要对树的每一层进行遍历,每一层的结点数=rear-head
        而在遍历每一层过程中,要对各个结点左右孩子进行入队,此时rear又要变化
        所以定义一个preRear,根据这个preRear控制对当前层的遍历
        */
        int preRear = rear;
        res[*returnSize] = (int*)malloc(sizeof(int) * (preRear - head));   //记录当前行的各个结点的值
        (*returnColumnSizes)[*returnSize] = preRear - head;                //记录当前行的列数
        int col = 0;
        //遍历当前行
        for (; head < preRear; head++) {
            struct TreeNode* tmp = queue[head];   //出队
            res[*returnSize][col++] = tmp->val;   //将出队结点的值放入res对应行对应列的位置
            //左右孩子入队
            if (tmp->left) {
                queue[rear++] = tmp->left;
            }
            if (tmp->right) {
                queue[rear++] = tmp->right;
            }
        }
        (*returnSize)++;  //当前行处理完毕,行数+1
    }
    return res;
}

运行,测试通过
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

知初与修一

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

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

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

打赏作者

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

抵扣说明:

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

余额充值