二叉树最大宽度-广度优先方式 -队列应用_20230520

news2024/11/24 19:52:04

二叉树最大宽度-广度优先(BFS)方式 -队列应用

  1. 前言

上一遍介绍了求解二叉树最大宽度的DFS解法,求解的核心主要是对根节点、左孩子及右孩子的宽度取最大值,通过赋值给根节点后,然后通过递归栈层层返回,当返回至树的根节点上的时候,求解出二叉树的最大宽度。其核心思想为DFS的后续遍历,对后续遍历的结果进行处理后,然后逐层返回。

本文探讨如何利用广度优先的方式求解二叉树的最大宽度,广度优先遍历通常配合队列一起进行,它的遍历方式同深度优先遍历不同,是按照逐层进行二叉树的遍历,直至最后一层遍历完成。

具体看一个例子,下图的二叉树,如果采用广度优先遍历的方式,

那么结点的遍历依次为①–>③–>②–>⑤–>⑦–>⑨,一般情况是需要借助队列的数据结构,通过不断的入队和出队,实现所有的遍历过程。

在这里插入图片描述

  1. 算法讨论

要通过BFS实现最大宽度的求解,我们需要按照二叉树的性质对存在的每个结点进行重新编号,如果根节点的编号定义为i,那么其左孩子编号定义为2*i, 右孩子的编号定义为2*i+1。不同于DFS的实现过程,可以采用递归变量对其编号进行保留记忆,在BFS算法中,我们需要对入队列的节点重新进行定义,它至少包含三个特性:

  • 二叉树结点本身
  • 二叉树结点所在的层次(深度)
  • 二叉树结点根据上述定义,计算出来的编号

根据上述数据特征,可以定义一个结构体,作为队列里的基本元素,随着BFS的不断进行,我们不断进行入队和出队的相应操作,操作过程中,不断对其三个特性进行相关的赋值操作。

实际操作过程中,需要对最左端的非空结点的序列号进行保存,作为后续同一层宽度计算的基础点;如果从出队的元素的层次号(深度)发生变化,此时需要更新最左侧的结点序列号,以确保另外一层的结点的基准正确。实际操作过程中,可以采用变量交替的方式实现这个操作。

我们可以对每个结点的宽度进行比较,选取最大的值进行返回,就可以求助整棵二叉树的最大宽度。

  1. 具体代码

由于C语言中没有提供队列的关键实现函数,读者可以参考《数据结构》(严蔚敏)里面的介绍自行实现,本文应用到的队列的实现方式介绍来自此教材。

上面提到,我们需要定义队列的结点,以便涵盖更多的信息,利于出队/入队的相关操作,定义新的结构体作为队列的基本元素。在TriNode结构体当中,容易发现node指针保存二叉树中遍历到的当前的指针,index保留当前结点的编号,它根据其父节点编号计算而成,在入队时自动生成,depth变量保存当前结点所在的层次(深度),如果出队的元素的层次有变化,我们需要对index重新进行赋值,作为当前层(深度)的基准点,以便正确计算后面元素的宽度(宽度跨度)。

typedef struct BiTNode
{
    int val;
    struct BiTNode *lchild;
    struct BiTNode *rchild;
} BiTNode, *BiTree;

typedef struct TriNode
{
    BiTNode *node;
    int    index;
    int    depth;
}TriNode;

3.1 头文件

/**
 * @file max_width.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-05-20
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef MAX_WIDTH_H
#define MAX_WIDTH_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))

typedef struct BiTNode
{
    int val;
    struct BiTNode *lchild;
    struct BiTNode *rchild;
} BiTNode, *BiTree;

typedef struct TriNode
{
    BiTNode *node;
    int    index;
    int    depth;
}TriNode;

typedef TriNode QElemType_L;

#include "../../../../Data_Structure_TingHua University/Textbook/ch03/07_LinkQueue/LinkQueue.c"

void create_bitree(BiTree *T, FILE *fp);

int max_width_of_binary_tree(BiTree root);



#endif

3.2 函数实现

可以返现实现本问题的关键函数为max_width_of_binary_tree,我们首先定义变量queue并对其进行初始化,初始化完成后,我们对根节点、结点编号、层数构成的结构体进行入队操作。值得一提的是,我们分别定义了depth和index,可以理解为动态出队的结点层数和结点编号,同时定义了pre_depth和pre_index分别代表当前的层数和最左侧非空结点的编号(基准点)。

然后利用循环语句对二叉树里面的元素进行出栈和入栈操作,先进行出栈操作,并判断出栈的结点是否为某层的最左端的第一个非空结点,如果满足这个条件,我们就对pre_depth和pre_index进行更新分别记录当前的层数和最左侧非空结点的编号。

最后对二叉树的左右子树分别进行检查,如果为非空结点,那么就按照上面提到的新节点的三个特性,构建一个新的队列结点进行入队操作,由于队列的特性,我们先处理左孩子结点,后处理右孩子结点。

重复上述操作直至队列里面的元素为空,此时就代表我们遍历完成所有的二叉树结点,并且对每个结点的宽度进行了计算和比较,已经获得了最大宽度值。

/**
 * @file max_width.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-05-20
 * 
 * @copyright Copyright (c) 2023
 * 
 */
#ifndef MAX_WIDTH_C
#define MAX_WIDTH_C
#include "max_width.h"

int max_width_of_binary_tree(BiTree root)
{
    int depth;
    int index;
    int pre_depth;
    int pre_index;
    int res;

    BiTree p;
    TriNode node;
    LinkQueue queue;

    InitQueue(&queue);

    node.depth=1;
    node.index=1;
    node.node=root;

    EnQueue(&queue,node);
    pre_depth=pre_index=0;
    res=0;

    while(!QueueEmpty(queue))
    {
        DeQueue(&queue,&node);

        depth=node.depth;
        index=node.index;

        if(depth>pre_depth)
        {
            pre_depth=depth;
            pre_index=index;
        }

        res=MAX(res,index-pre_index+1);

        if(node.node->lchild)
        {
            EnQueue(&queue, (TriNode){node.node->lchild, index * 2, depth + 1});
        }

        if (node.node->rchild)
        {
            EnQueue(&queue, (TriNode){node.node->rchild, index * 2 + 1, depth + 1});
        }
    }

    return res;

}



void create_bitree(BiTree *T, FILE *fp)
{
    int val;

    // printf("Please input the integer\n");
    fscanf(fp, "%d", &val); // 1,2,3,-1,-1,4,-1,-1,2,4,-1,-1,3,-1,-1

    if (val == -1)
    {
        *T = NULL;
    }
    else
    {
        *T = (BiTree)malloc(sizeof(BiTNode));
        (*T)->val = val;
        create_bitree(&((*T)->lchild), fp);
        create_bitree(&((*T)->rchild), fp);
    }

    return;
}

#endif

3.3 测试函数

/**
 * @file max_width_main.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2023-05-20
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef MAX_WIDTH_MAIN_C
#define MAX_WIDTH_MAIN_C
#include "max_width.c"

int main(void)
{
    BiTree root;
    int max_width;
    FILE *fp;

    fp = fopen("data.txt", "r");

    create_bitree(&root, fp);

    max_width=max_width_of_binary_tree(root);

    printf("The actions had been done\n");
    getchar();
    fclose(fp);
    return EXIT_SUCCESS;
}

#endif

测试数据data.txt文件

1
3
5
-1
-1
7
-1
-1
2
-1
9
-1
-1
  1. 小结

通过本示例学习,加深了对BFS遍历的深入理解,也灵活对原有二叉树的结点进行增强,进行出队/入队的相关操作,最终求得所需结果。

参考资料:

662. 二叉树最大宽度 - 力扣(Leetcode)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/552648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字图像处理—图像分割算法详解(边缘检测、阈值处理)

前言 令R表示一幅图像占据的整个空间区域。图像分割&#xff1a;把R分为n个子区域R1,R2,…,Rn的过程&#xff0c;满足 点、线、边缘检测 背景知识 一阶导数的近似要求&#xff1a; &#xff08;1&#xff09;在恒定灰度区域必须为零 &#xff08;2&#xff09;在灰度台阶或…

【连续介质力学】张量值张量函数

张量值张量函数 张量值张量函数有以下类型&#xff1a;标量&#xff0c;向量和高阶张量 标量值张量函数&#xff1a; Ψ Ψ ( T ) det ⁡ T Ψ Ψ ( T , S ) T : S \Psi \Psi(T) \det T \\ \Psi \Psi(T,S) T:S ΨΨ(T)detTΨΨ(T,S)T:S 其中&#xff0c; T , S T, S …

【JavaEE】MyBatis + 单元测试

目录 MyBaits项目的创建使用 引入相关依赖 配置文件设置 数据库连接 配置XML路径 映射器文件模板 业务代码实例 创建实体类 添加Mapper接口创建映射器 验证是否成功 MyBatis原理 什么是MyBatis 为什么学习MyBatis MyBatis工作原理 单元测试 前置工作 生成测试…

Selenium是什么,带你了解自动化测试的神奇之处

一、使用测试工具 工欲善其事&#xff0c;必先利其器。在开始具体的自动化测试之前&#xff0c;我们需要做好更多的准备&#xff0c;包括以下几个方面&#xff1a; 认识自动化测试 准备自动化测试工具 使用有效的方式 针对具体的测试对象 接下来的第一部分内容&#xff0c;我…

基于Java web的电子商务系统

摘要 【摘要】 所谓电子商务就是在网上开展商务活动&#xff0c;当企业将它的主要业务通过企业内部网&#xff08;Intranet&#xff09;、外部网&#xff08;Extranet&#xff09;以及Internet与企业的职员、客户供销商以及合作伙伴直接相连时&#xff0c;其中发生的各种活动就…

基于SpringBoot的校园志愿者管理系统的设计与实现

背景 本次设计任务是要设计一个校园志愿者管理系统&#xff0c;通过这个系统能够满足管理员和志愿者的校园志愿者信息管理功能。系统的主要功能包括首页、个人中心、志愿者管理、活动类型管理、活动信息管理、活动报名管理、活动通知管理、活动心得管理、交流反馈、系统管理等…

【LTspice入门】一、LTspice安装

一、LTspice安装 1、仿真的重要性&#xff1a;2、LTspice介绍3、LTspice官网4、LTspice下载与安装 1、仿真的重要性&#xff1a; 掌握好电路仿真有助于加深对电子电路分析理论的理解。 由于电子电路仿真不需要实际的元件和仪器仪表设备,设计者就可以对所涉及的电子电路进行性能…

PCIE总线基本介绍(和PCI总线差异、速率计算、引脚定义)

1、PCI和PCIE的差异 (1)PCIE协议在软件编程上是兼容PCI协议&#xff0c;不同在于PCIE和PCI的控制器&#xff1b; (2)PCIE是差分串行信号线&#xff0c;PCI是电平并行信号线&#xff1b; (3)PCI协议使用INTA#、INTB#、INTC#、INTD#四根中断线来触发终端&#xff0c;PCIE协议没有…

sshd_conf 配置文件详解

/etc/ssh/sshd_config配置文件内容详解。 Port 22 设置SSHD监听端口号。 SSH 预设使用 22 这个port&#xff0c;也可以使用多个port&#xff0c;即重复使用 port 这个设定项&#xff01;例如想要开放SSHD端口为 22和222&#xff0c;则多加一行内容为&#xff1a; Port 222 即…

kotlin协程async与await

kotlin协程async与await import kotlinx.coroutines.* import kotlin.system.measureTimeMillisfun main() {val time measureTimeMillis {runBlocking {/*** async 是 CoroutineScope 扩展函数&#xff0c;async 和 launch 的区别在于async 可以返回协程结果&#xff0c;而 l…

【002hive基础】hive的库、表与hdfs的组织逻辑

文章目录 一. 数据的组织形式1. hive数据库2. hive表2.1. 内部表和外部表2.2. 分区表与分桶表 3. 视图 二. 底层储存 一. 数据的组织形式 1. hive数据库 hive将不同功能模块的数据&#xff0c;存储在不同的数据库中&#xff0c;在hdfs中以文件夹的形式显示。 2. hive表 2.1.…

Excel统计函数AVEDEV,稳住我们能赢

你的关注&#xff0c;是我最大的动力&#xff01;你的转发&#xff0c;我的10W&#xff01;茫茫人海有你的支持&#xff0c;给我无限动力。 1、AVEDEV函数。 &#xff08;1&#xff09;说明。 返回一组数据点到其算术平均值的绝对偏差的平均值。 AVEDEV函数是对一组数据中变化…

Linux---phy外设调试

文章目录 一、phy设备概述二、内核驱动配置与设备树添加三、其他补充 一、phy设备概述 我们知道在计算机网络上有一个OSI 7层模型&#xff1a; 应用层&#xff1a;网络服务与最终用户的一个接口。 协议有&#xff1a;HTTP FTP TFTP SMTP SNMP DNS TELNET HTTPS POP3 DHCP 表…

服务(第二十七篇)squid-传统、穿透、反向代理

squid代理服务器&#xff1a; 主要提供缓存加速、应用层过滤控制的功能。 代理的工作机制&#xff1a; 1、代替客户机向网站请求数据&#xff0c;从而可以隐藏用户的真实IP地址。 2、将获得的网页数据&#xff08;静态 Web 元素&#xff09;保存到缓存中并发送给客户机&#x…

【Anaconda+Pytorch+DGL】安装+配置详细过程

文章目录 Anaconda安装1、进入[Anaconda官网](https://www.anaconda.com/)下载&#xff0c;下载完成后安装指令默认直到完成安装。2、进入Anaconda Prompt&#xff0c;使用conda指令来为不同的版本创建单独的环境&#xff1a; Pytorch安装1、打开NVIDIA控制面板&#xff0c;帮助…

Python+Yolov5水稻病害侦测识别

程序示例精选 PythonYolov5水稻病害侦测识别 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<PythonYolov5水稻病害侦测识别>>编写代码&#xff0c;代码整洁&#xff0c;规则&am…

gcc/g++ 、Make/Makefile、CMake/CMakeLists.txt、qmake关系简述

1、gcc与g 首先来了解下编译器的主要工作流程&#xff1a; 源码&#xff08;Source Code&#xff09;>> 预处理器&#xff08;Preprocessor&#xff09;>> 编译器&#xff08;Compiler&#xff09; >> 汇编程序&#xff08;Assembler&#xff09;>> …

深度学习踩坑经验沉淀【持续更新】

背景 在深度学习炼丹过程中&#xff0c;总会遇到各种奇怪问题&#xff0c;这个时候总会在csdn和知乎平台找到答案&#xff0c;那每次遇到的问题是解决了&#xff0c;但没有记录起来&#xff0c;确实太可惜&#xff0c;因为未来某个时间或者某个人会遇到类似问题&#xff0c;所…

HBase应用场景和最佳实践

HBase 作为 Apache 基金会的 Hadoop 项目的一部分&#xff0c;将 HDFS 作为文件存储系统&#xff0c;使用 MapReduce 进行分布式的数据批量处理&#xff08;非实时数据批量处理&#xff09;、利用Zookeeper提供协同管理服务&#xff0c;为 Hadoop 提供海量数据管理服务&#xf…

ROS学习(5)——话题消息与服务

节点之间的消息通信分为几种形式&#xff1a; 话题(topic):单向消息发送/接收方式服务(service):双向消息请求/响应方式动作(action):双向消息目标(goal)/结果(result)/反馈(feedback)方式参数服务器(参数共享模式) 种类区别话题异步单向连续单向的发送/接收数据的情况服务同步…