二叉树最大宽度_深度优先方式_20230520

news2024/11/18 3:49:43

二叉树最大宽度_深度优先方式_20230520

  1. 前言

给定一颗二叉树,求解其最大宽度。定义每层宽度为该层最左和最右之间的长度,也即左右两个端点之间的所跨越的长度,两个端点直接可能会包含一些延伸到本层的空节点,这些空节点的长度由于占据了宽度符,所以也计入长度范围内。

此问题的常规解法包含广度优先和深度优先两种方式,每种方式都需要对二叉树结点重新进行线性化编号,类似Heap结点的编号规则,定义根节点的编号为index, 那么其直接左孩子结点的编号为2*index,同理其直接右孩子结点编号为2*index+1。

在这里插入图片描述

  1. 深度优先遍历

深度优先遍历,顾名思义,访问节点过程中,先从深度方向上对节点进行遍历,通过不断递归,最终访问所有的节点,要用深度优先方式求解此题,先看一个最基础的例子。以三个节点二叉树为例进行思路的阐述。

在这里插入图片描述

要求解树的宽度,先访问节点③,节点③的宽度为1;然后访问节点⑤,节点⑤的宽度也为1;最后对节点⑦进行访问,节点7的宽度为2. 在深度优先遍历过程中,需要比较根节点,左孩子节点以及右子树节点的宽度,选择三个中的最大值,赋予根节点,然后再不断的递归回退。
r o o t _ w i d t h = M A X ( r o o t _ w i d t h , l e f t _ c h i l d _ w i d t h , r i g h t _ c h i l d _ w i d t h ) root\_width=MAX(root\_width,left\_child\_width,right\_child\_width) root_width=MAX(root_width,left_child_width,right_child_width)
最后求得根结点代表的子树的最大宽度值为2。

如果把上述例子作为求解的最基础的实例,那么我们再将上述公式进行一般化处理,再看一个具体的例子。

在这里插入图片描述

如果采用递归遍历,按照前面的例子,完成结点③代表的左子树的最大宽度求解后,结点③代表的左子树的最大宽度值为2。

然后再对结点②代表的右子树的最大宽度进行求解,结点②本身的宽度为2,其左子树为空,那么默认其宽度为0,其右子树⑨的宽度为4,利用上述公式,以结点②为基础的右子树的最大宽度值为4。

再接着回退,对根节点①,其左结点③和右结点②进行宽度最大值的求解,最终根节点最大宽度更新为4。

在深度优先遍历过程中,面临的挑战之一为如何求解层中每个结点相对于左端点的最大宽度,深度优先遍历对每层中结点的访问次序并不是连续的,无法在遍历过程中,直接利用其前置结点的值。这种情况下,就需要对每次的最左侧的非空结点的位置进行储存记忆,同时在递归函数中需要追踪目前处理的结点在哪一层上,方便查询并求出宽度。

如果以上面的二叉树为例,那么我们需要记录第一层结点的①min_depth[1]的值为1,第二层结点③的min_depth[2]为2,第三层结点⑤的min_depth[3]为4,这三个值一旦确定,后续遍历过程中便不再进行更新,需要通过当前深度进行查询,然后和当前结点位置进行比较,最终求出其最大的宽度值。

以结点⑨为例,它本身的计算结点编号为7(2*3+1),它所在的层数 (深度)为3,通过数组查询min_depth[3]为4,那么结点⑨的最大宽度值:
M a x _ w i d t h   o f   n o d e  ⑨ = 7 − 4 + 1 = 4 Max\_width\ of\ node\ ⑨ = 7-4+1=4 Max_width of node =74+1=4
如果二叉树的深度比较小,那么可以采用普通的数组进行储存与查询,规定数组中的初值为-1,当深度遍历第一次访问到左节点的时候,更新其值为正确的值,后续对于相同的深度的节点则不再进行更新。

  1. 程序实现

基于上面的分析,则程序的实现就比较简单,主要是在递归回退过程中,对左子树、右子树和根的宽度进行比较,返回最大值即可,这种递归过程可以直观理解为层层返回,根据条件对值进行更改,最终在总的根节点上求出问题的答案。

由于需要追踪访问过程中的每个节点所在的层数(深度)和其线性化的编号,所以递归函数的设计,不仅仅需要节点,还需要记录层数的变量depth和线性化编号的变量index。

为了简化递归函数,我们定义记忆数组min_depth[]为全局变量,并在递归第一次到达当前层的时候,对数组的内容给予更新,同时利用init_array函数对其所有元素赋初值为-1。

3.1 头文件定义

/**
 * @file max_width.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-05-19
 * 
 * @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_DEPTH 10
#define MAX(a, b) ((a) > (b) ? (a) : (b))
int     min_index[MAX_DEPTH];


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

/*
利用先序遍历建立二叉树,如果值为-1,则默认为NULL
*/
void create_bitree(BiTree *T, FILE *fp);

/*
初始化min_depth数组所有元素为-1
*/
void init_array(int *arr,int n);

/**
 * @brief 
 * By using DFS to find the solution to maximum width of binary tree
 * it will return the maximum widhth of (root_width, left_child_width,right_child_widht)
 * @param root   Root node 
 * @param depth  Indidctor of depth of current node
 * @param index  Linear sequence index of current node(similar to heap number)
 * @return int   Return the max width of whole tree
 */
int max_width_of_binary_tree(BiTree root, int depth, int index);

#endif

3.2 关键函数的实现

/**
 * @file max_width.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2023-05-19
 * 
 * @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)
{
    if(root==NULL)
    {
        return 0;
    }

    int root_width;
    int l_width=0;
    int r_width=0;

    if (min_index[depth]==-1)
    {
        min_index[depth]=index;
    }

    root_width = index - min_index[depth] + 1;

    if(root->lchild)
    {
        l_width=max_width_of_binary_tree(root->lchild,depth+1,index*2);
    }
    if(root->rchild)
    {
        r_width=max_width_of_binary_tree(root->rchild,depth+1,index*2+1);
    }

    root_width=MAX(MAX(root_width,l_width),r_width);

    return root_width;

}

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

    // printf("Please input the integer\n");
    fscanf(fp, "%d", &val); 

    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;
}

void init_array(int *arr, int n)
{
    int i;

    for(i=0;i<n;i++)
    {
        *(arr+i)=-1;
    }
}

#endif

3.3 测试函数

/**
 * @file max_width_main.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2023-05-19
 *
 * @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);
    init_array(min_index,MAX_DEPTH);

    max_width=max_width_of_binary_tree(root,1,1);

    printf("The max_width is %d\n the action had been done\n",max_width);
    getchar();
    fclose(fp);
    return EXIT_SUCCESS;
}

#endif

测试数据data.txt

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

利用深度优先遍历求解二叉树的最大宽度过程是不断对当前根、左孩子及有孩子的宽度求最大值的过程,求解过程部分属于后续遍历,此时左、右两个孩子的宽度都已经被函数栈弹回值l_width和r_width两个变量中,它们需要和根节点的宽度(root_width)进行比较,然后把最大值赋给给节点。

这个过程和线段树求解最大值的过程有点类似,有时候可以形象理解为,函数栈的值在弹出过程中,根据条件进行计算,然后再把新的值传递给上一层根节点,直至求解出最终的结果。

参考资料:

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

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

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

相关文章

【小沐学NLP】Python实现聊天机器人(OpenAI,模型概述笔记)

&#x1f37a;NLP开发系列相关文章编写如下&#x1f37a;&#xff1a;1&#x1f388;【小沐学NLP】Python实现词云图&#x1f388;2&#x1f388;【小沐学NLP】Python实现图片文字识别&#x1f388;3&#x1f388;【小沐学NLP】Python实现中文、英文分词&#x1f388;4&#x1…

Springcloud1----->Hystrix

目录 雪崩问题服务降级原理实践order降级处理user降级处理 服务熔断原理实践 hystrix&#xff0c;英文意思是豪猪&#xff0c;全是是刺&#xff0c;一种保护机制&#xff0c;即熔断器。 主页&#xff1a;https://github.com/Netflix/Hystrix/ 雪崩问题 在微服务中&#xff0c;…

selenium自动化测试报告_selenium自动化测试断言

一、元素操作方法 方法&#xff1a; 1、.send_keys() # 输入方法 2、.click() # 点击方法 3、.clear() # 清空方法 复制 注意&#xff1a;在输入方法之前一定要清空操作!! # 导包 from time import sleep from selenium import webdriver# 实例化浏览器 driver webdriver…

这才是自动化测试,资深测试构建持续交付体系(高质量)持续集成...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 软件测试-自动化测…

OptimizePI仿真流程

OptimizePI软件介绍 OptimizePI是用于针对PI设计进行优化的一个设计流程&#xff0c;可以针对PDN的设计进行仿真计算&#xff0c;主要功能包括以下几个&#xff1a; PDN前仿真分析PDN后仿真分析PDN阻抗检查去耦电容的回路电感分析芯片的电源管脚的电感分析去耦电容最佳位置评…

一文参透AB斗篷的前世今生

做FP独立站的应该都对cloak斗篷不陌生&#xff0c;cloak已经成为出海营销行业的必备工具之一。尽管使用cloak并不能保证一定有效&#xff0c;但不使用cloak却也是不可行的。今天本文将详细讲解cloak系统的“前世今生”&#xff0c;以便让大家更好地了解cloak系统并能挑选到最适…

【中间件】通过 docker-compose 快速部署 Zookeeper 保姆级教程

文章目录 一、概述二、前期准备1&#xff09;部署 docker2&#xff09;部署 docker-compose 三、创建网络四、Zookeeper 编排部署1&#xff09;下载 Zookeeper2&#xff09;配置3&#xff09;启动脚本 bootstrap.sh4&#xff09;构建镜像 Dockerfile5&#xff09;编排 docker-c…

如何使用ChatGpt来学习和提问【对话ChatGPT】?

ChatGPT的不断发展和进步&#xff0c;我们需要工作中很多时候会用到ChatGPT&#xff0c;那么如何使用ChatGPT来解决我们工作中的问题呢&#xff1f; Q1如何向ChatGPT提问&#xff0c;从而更快解决我们的问题&#xff1f; ChatGPT&#xff1a;以下是向ChatGPT提问的一些提示&a…

CISSP和Security+的区别和学习建议

当谈到网络安全认证时&#xff0c;经常有朋友问我CISSP 与 Security认证。两者都是业内比较认可&#xff0c;对实际工作有所帮助的认证&#xff0c;但是哪一个适合自己呢&#xff0c;区别又是什么呢&#xff1f; 在深入研究细节之前&#xff0c;让我们先简要了解一下 CISSP 与 …

深度学习之自编码器实现——实现图像去噪

大家好&#xff0c;我是带我去滑雪&#xff01; 自编码器是一种无监督学习的神经网络&#xff0c;是一种数据压缩算法&#xff0c;主要用于数据降维和特征提取。它的基本思想是将输入数据经过一个编码器映射到隐藏层&#xff0c;再通过一个解码器映射到输出层&#xff0c;使得输…

数字宁夏“1244+N”行动进行时,实在智能以AI为宁夏全区县数字化转型加“数”度

建设数字中国是数字时代推进中国式现代化的重要引擎&#xff0c;是构筑国家竞争新优势的有力支撑。现如今&#xff0c;政府部门发展数字经济已然成为新科技浪潮下的战略选择。可以预见&#xff0c;在数字化浪潮的推动下&#xff0c;中国经济将迎来新的高峰。 近日&#xff0c;宁…

English Learning - L3 作业打卡 Lesson2 Day13 2023.5.17 周三

English Learning - L3 作业打卡 Lesson2 Day13 2023.5.17 周三 引言&#x1f349;句1: A blacklist is illegal now.成分划分弱读爆破语调 &#x1f349;句2: But at one time, some businesses refused to employ people who were on a blacklist for belonging to unpopular…

【正点原子STM32连载】 第十一章 STM32时钟配置 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第十一…

log4net在Asp.net MVC4中的使用

1、安装log4net插件 新建Asp.net MVC4项目&#xff0c;并在Nuget控制台输入命令&#xff0c;或者直接搜索log4net在线安装&#xff0c;安装log4net >Install-Package log4net -Version 2.0.15 2、配置web.config文件 <?xml version"1.0" encoding"ut…

小试牛刀:应用深度强化学习优化文本摘要思路及在裁判文书摘要上的实践效果

一、引言 近期&#xff0c;随着大模型的出现&#xff0c;强化学习再一次的引起了本人的兴趣&#xff0c;本文将应用深度强化学习来优化文本摘要模型&#xff0c;使生成的摘要更加的流畅。在此之前&#xff0c;大家都采用了很多种方式训练摘要系统&#xff0c;例如&#xff1a;…

MySQL的主从实战

MySQL的主从实战 1、Mysql主从的必要性 访问量不断增减&#xff0c;Mysql服务器的压力增大&#xff1b;就需要对Mysql进行优化与改造&#xff1b; 实现Mysql的高可用MySQL的主从复制搭建 主从搭建的目的就是实现数据库冗余备份同步主服务器和Slave服务器&#xff0c;一旦Mas…

Vivado综合属性系列之七 DONT TOUCH

目录 一、前言 二、DONT TOUCH ​ ​2.1 属性说明 ​ ​2.2 属性用法 ​ ​2.3 工程代码 ​ ​2.4 参考资料 一、前言 ​ ​设计中经常会遇到一些信号&#xff0c;模块等被综合工具优化&#xff0c;而实际这些部分确是我们所需要的&#xff0c;针对这种情况&a…

哨兵机制原理详解

文章目录 初始化 Sentinel三个定时任务&#xff08;重要&#xff09;INFO任务订阅/发布任务心跳任务 Redis节点下线判断主观下线判断客观下线判断 Sentinel Leader 选举故障转移过程整体过程Master 选择算法修改从服务器的复制目标将旧的主服务器变为从服务器 节点上线原Redis节…

如何用Nginx实现对国家/城市以及指定IP的访问限制?

1.前言 在【如何用Nginx代理MySQL连接&#xff0c;并限制可访问IP】一文中&#xff0c;我们实现了通过Nginx代理MySQL连接&#xff0c;并限制了指定IP才能通过Nginx进行连接&#xff0c;以提高数据安全性。 该场景适用于根据具体的IP地址来进行访问限制&#xff0c;假如我们要…

synchronized优化原理

文章目录 一、Monitor1.1 Monitor结构 二、轻量级锁三、锁膨胀四、自旋优化五、偏向锁 一、Monitor Monitor的工作原理也是synchronized底层原理 每个Java对象都可以关联一个Monitor对象&#xff0c;如果使用synchronized给对象上锁之后&#xff0c;该对象头的MarkWord中就被设…