数据结构+算法(第09篇):菜鸟也能“种”好二叉树!

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

引言

在本系列第5篇《小白也能玩转数组和链表啦!》中,给出了常用数据结构的全貌图:

本文就来讲讲“树”这个数据结构。

1. 树的本质是什么?

本系列第2篇《扫雷还可以这样玩》中提到了算法问题的基本类型——搜索、排序、规划、计算。其中,搜索和排序与生活中朴素的体验息息相关。

我们每个人都有如下体验:

如果房间乱七八糟,那么找一样东西相当棘手。

收拾好房间之后,找东西就容易多了。收拾的过程就是分类、整理的过程。

当东西特别多时,往往一个分类还不够——这会导致该分类下的东西太多,找起来仍然很花时间。但是直接简单增加分类的话,当分类增加到一定程度,我们查找分类的时间就会变长。那么怎么解决这个矛盾呢?

方法就是给分类进行分层。每一层只有几个类,每个类再往下一层分成更细的几个类,以此类推。通过这种方法,每查找一层的时候,只用对付几个类即可。

人的大脑是通过神经元之间的连接进行思考的,神经元的排列和连接也是分层的。这样的生理结构导致我们适合做分层分类的处理。

现代科学理论也是按照这样的分层分类的方式进行组织的,源头可以追溯到古希腊的数学家欧几里得。

当年他就是用这样的分层分类的“公理化”方法,将那个时代的几何知识进行了有效组织,,写成了不朽的巨著《几何原本》,使得原本分散的海量结论,通过这样的整理,便于后人高效掌握。

这种方式,也被大名鼎鼎的物理学家恩斯特·马赫称为“智力经济”。

如果把每一个分类用一个节点来表示,位于相同层次的分类放在一行,那么整个组织结构就如下图所示:

看起来是不是像一颗倒过来的树?

综上所述:树的本质就是一种用于高效搜索的数据结构。

更进一步,如果树中的节点之间还有排序关系,那么搜索还会加速。

二叉树

既然讨论分类,我们就从最简单、最常用的分类——二元分类开始研究。所谓的二元分类,用通俗的话来说就是:非黑即白。对应到树的结构,如下图所示:

它的特点就是:每个节点最多只有两个分支(子节点)。

2. 二叉树的数据结构表达

从上图可以看出,整棵树其实就是一个递归结构。递归的基本单元就是节点。每个节点有三个信息:

节点本身承载的数据、节点的左子节点、节点的右子节点。

这三个信息在具体的编程语言中,可以用一个结构体或者类来表达。

这里以Java作为示例:

    class BinaryNode<T> {
    T node_item;BinaryNode<T> left_child;BinaryNode<T> right_child;
    }

节点集合起来就是一棵树。

那么怎样集合起来呢?回头看看本文开头的那张数据结构全貌图,所有的数据结构都可以用作集合。本系列第5篇《小白也能玩转数组和链表啦!》中介绍的数组和链表就是常用的用来将节点组织成树的数据结构。

换言之,二叉树这个数据结构是由数组或者链表这样的基础数据结构复合而成。

2.1 二叉树的链表复合形式

节点之间通过left_child和right_child勾连起来就形成了树。

假设有一组节点Node_0、Node_1、Node_2、Node_3,Node_4,Node_5,它们之间的关系如下:

那么用链表复合就是通过如下代码:

    Node_0.setLeftChild(Node_1);
    Node_0.setRightChild(Node_2);
    Node_1.setLeftChild(Node_3);
    Node_1.setRightChild(Node_4);
    Node_2.setLeftChild(Node_5);
    Node_2.setRightChild(null); // 没有对应的子节点,就设置为空节点

其中setLeftChild()定义成设置左子节点的方法:

    public void setLeftChild(BinaryNode<T> left) {
    this.left_child = left;
    }

setRightChild()定义成设置右子节点的方法。

    public void setRightChild(BinaryNode<T> right) {
    this.right_child = right;
    }

2.2. 二叉树的数组复合形式

按照从上到下、从左到右的顺序,可以依次将各节点放入一个数组:

数组的第0号元素是树的根节点(node_0),第1号元素是根节点的左子节点(node_1),依此来推。

3. 完全二叉树

如果一棵二叉树,除了末尾的那些节点外,其他节点都是两个分支(子节点),那么这样的二叉树就叫作“完全二叉树”:

将完全二叉树用空节点补齐,就成为了满二叉树。

5. 为什么研究完全二叉树和满二叉树?

因为完全二叉树和满二叉树有比较好的性质,这样的性质可以被用于高效搜索、排序。

5.1 深度与节点总数的关系

先来看满二叉树。

由满二叉树的定义可知:每个节点都在下一层“裂变”成2个节点。如果当前层的节点总数为N的话,那么下一层的节点总数就是2N。假若我们记第h层的节点总数为f(h),那么:

    f(1):f(2):f(3): ... :f(n)=1:2:4: ... :2^(h-1) (式1)

显然这构成一个等比数列。

整个满二叉树(假设总共h层)的节点总数M等于:

    f(1)+f(2)+f(3)+...+f(h)=1+2+4+...+2^(h-1)

根据等比数列求和公式得到:

    M=f(1)+f(2)+f(3)+...+f(h)=1+2+4+...+2^(h-1)=2^h-1(式2)

h其实代表树的深度,对上式两边取以2为底的对数,得到:

    h=logM (式3)

如果是完全二叉树,假设:

(1)该完全二叉树的节点总数是m、深度是h;

(2)将它“补全”的满二叉树的节点总数是M、深度是H;

(3)将它“补全”的满二叉树的深度是H;

那么根据完全二叉树和满二叉树的定义可知:

    H-1<h<=H(式4)M-m<=f(H) (式5)

将式3代入式4得到:

    logM-1<h<=logM(式6)

将式1打入式5得到:

    M-m<=2^(H-1)(式7)

5.2 节点与子节点位置的线性关系

从完全二叉树的数组复合形式表达可以发现:

第0号元素所代表的节点,它的左子节点是数组的第1号元素,它的右子节点是数组的第2号元素;

第1号元素所代表的节点,它的左子节点是数组的第3号元素,它的右子节点是数组的第4号元素……

看出什么规律了吗?

    1=2x0+12=2x(0+1)3=2x1+14=2x(1+1)

推论5.2.1

数组第n号元素所代表的节点,它的左子节点是数组的第(2n+1)号元素,它的右子节点是数组的第2(n+1)号元素

根据上述推论,我们发现一个重要事实:

每个节点的左子节点和右子节点在数组中的位置是可以直接由该节点在数组中的位置决定的。

既然相互之间的位置可以直接决定,那么也就没有必要在每个节点的数据结构中保存左子节点和右子节点的信息了,只用保留节点本身的信息node_item即可。

6. 完全二叉树性质的应用

还记得上一篇《史上最猛之递归屠龙奥义》中的反转二叉树的题目吗?今天我们就利用满二叉树的节点与子节点位置的线性关系来巧解这道题:

反转二叉树就是递归交换左右子树,如果将整棵树用数组来保存,那么这个递归交换就可以翻译成:

遍历整个数组,对每个元素,找到它的左子节点所对应的数组元素、右子节点所对应的数组元素,将两者交换位置,就实现了整棵树的反转。

是不是很有意思呢?

7. 下一步展望

看到这里,相信你对树已经有了扎实的理解。接下来我们的小汽车会逐步加速,带你畅游查找二叉树、平衡二叉树、B树和红黑树等高阶“乐园”。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023年网信办约谈了上万家网站

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 网信办发布公告&#xff1a; 网信办在共约谈网站 10646 家;责令 453 家网站暂停功能或更新;下架移动应用程序 259 款;关停小程序 119 款;取消违法网站许可或备案、关闭违法网站 14624 家;关闭违法违规账号 127878 个…

windows 谷歌浏览器Chrome 怎么禁止更新

1.首先把任务管理器里的谷歌浏览器程序结束&#xff1a; &#xff08;鼠标在任务栏右击&#xff0c;出现任务管理器&#xff09; 2.windowr&#xff0c;输入services.msc 带有Google Update的服务&#xff0c;选择禁用。 3.windowr&#xff0c;输入taskschd.msc 任务计划程序…

CTF-WEB进阶与学习

PHP弱类型 在进行比较的时候&#xff0c;会先判断两种字符串的类型是否相等&#xff0c;再比较 在进行比较的时候&#xff0c;会先将字符串类型转化成相同&#xff0c;再比较 如果比较一个数字和字符串或者比较涉及到数字内容的字符串&#xff0c;则字符串会被转换成数值 并且…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)--大模型、扩散模型、视觉

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起…

如何分辨坏信息?

每当有社会热点&#xff0c;大家也许都会遇到一个困扰&#xff1a; 铺天盖地的信息&#xff0c;实在是太多了。究竟哪一些值得信任&#xff0c;哪些不值得信任&#xff1f;哪些可以接受&#xff0c;哪些最好保持怀疑&#xff1f; 我想用这篇文章&#xff0c;彻底把这个问题讲清…

day32 买卖股票的最佳时机Ⅱ 跳跃游戏 跳跃游戏Ⅱ

题目1&#xff1a;122 买卖股票的最佳时机Ⅱ 题目链接&#xff1a;122 买卖股票的最大时机Ⅱ 题意 整数数组prices[i]表示某股票的第i天的价格&#xff0c;每天可买卖股票且最多持有1股股票&#xff0c;返回最大利润 利润拆分&#xff0c;拆分为每天的利润 每天的正利…

【演讲比赛流程管理系统(C++版)】

一、演讲比赛程序需求 1.1、比赛规则 学校举行一场演讲比赛&#xff0c;共有12个人参加。比赛共两轮&#xff0c;第一轮为淘汰赛&#xff0c;第二轮为决赛 每名选手都有对应的编号&#xff0c;如10001~10012 比赛方式:分组比赛&#xff0c;每组6个人 第一轮分为两个小组&a…

银行数据仓库体系实践(18)--数据应用之信用风险建模

信用风险 银行的经营风险的机构&#xff0c;那在第15节也提到了巴塞尔新资本协议对于银行风险的计量和监管要求&#xff0c;其中信用风险是银行经营的主要风险之一&#xff0c;它的管理好坏直接影响到银行的经营利润和稳定经营。信用风险是指交易对手未能履行约定契约中的义务而…

力扣热门100题刷题笔记 - 2.两数相加

力扣热门100题 - 2.两数相加 题目链接&#xff1a;2.两数相加 题目描述&#xff1a; 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。请你将两个数相加&#xff0c;并以相同形式返…

Python入门到精通(七)——Python文件操作

Python文件操作 一、文件的编码 二、文件的读取 1、操作汇总 2、model 常用的三种基础访问模式 三、文件的写入 四、文件的追加 五、综合案例 一、文件的编码 1、什么是编码&#xff1f; 编码就是一种规则集合&#xff0c;记录了内容和二进制间进行相互转换的逻辑。编…

强化学习 - Monte Carlo Tree Search (MCTS)

什么是机器学习 强化学习中的Monte Carlo Tree Search (MCTS) 是一种用于决策制定和搜索的算法&#xff0c;特别在不确定环境下表现出色。 1. 强化学习背景 在强化学习中&#xff0c;一个智能体通过与环境的交互学习&#xff0c;以便在某个任务上获得最大的奖励。MCTS是一种…

01- k8s基础网络知识 之 underlay与overlay网络

前言&#xff1a; 我们在学习k8s网络之前&#xff0c;必须要了解k8s网络相关的一些基础知识&#xff0c;比如什么是underlay网络、overlay网络等&#xff0c;只有把基础知识掌握之后&#xff0c;后续学习k8s网络的时候&#xff0c;一些知识点就不会再云里雾里了。 1 underlay与…

关于字符串处理

文章目录 关于字符串处理1、取字符串的长度2、跳过前面的字符3、取字符串右边的字符4、掐头去尾5、取倒数的范围6、删左留右7、删右留左8、查找替换9、大小写转换 关于字符串处理 1、取字符串的长度 [rootlocalhost ~]#strabcd1128 #定义变量 [rootlocalhost ~]#echo ${#str}…

React实现组件扩展机制

在java中&#xff0c;SPI机制是Java中提供的一种服务发现机制。同样&#xff0c;前端也很需要这种机制&#xff0c;这样可以做到组件可插拔&#xff0c;可替换&#xff0c;减少相互冗余。 快速使用 1.扩展点使用 通过使用Extension组件定义扩展点&#xff0c;通过name标记扩展…

血细胞分类项目

血细胞分类项目 数据集&#xff1a;血细胞分类数据集数据处理 dataset.py网络 net.py训练 train.py拿训练集的几张图进行预测 数据集&#xff1a;血细胞分类数据集 https://aistudio.baidu.com/datasetdetail/10278 数据处理 dataset.py from torchvision import transfor…

[晓理紫]每日论文分享(有中文摘要,源码或项目地址)

专属领域论文订阅 关注{晓理紫|小李子}&#xff0c;每日更新论文&#xff0c;如感兴趣&#xff0c;请转发给有需要的同学&#xff0c;谢谢支持 如果你感觉对你有所帮助&#xff0c;请关注我&#xff0c;每日准时为你推送最新论文。 为了答谢各位网友的支持&#xff0c;从今日起…

Task05:PPO算法

本篇博客是本人参加Datawhale组队学习第五次任务的笔记 【教程地址】https://github.com/datawhalechina/joyrl-book 【强化学习库JoyRL】https://github.com/datawhalechina/joyrl/tree/main 【JoyRL开发周报】 https://datawhale.feishu.cn/docx/OM8fdsNl0o5omoxB5nXcyzsInGe…

【QT+QGIS跨平台编译】之二十二:【FontConfig+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、FontConfig介绍二、文件下载三、文件分析四、pro文件五、编译实践 一、FontConfig介绍 FontConfig 是一个用于配置和定制字体的库&#xff0c;广泛应用于基于X Window系统的操作系统中&#xff0c;尤其是在Linux和Unix-like系统中。它为应用程序提供了一种统一的…

C语言·贪吃蛇游戏(上)

1. 游戏任务 使用C语言在Windows环境的控制台中模拟实现小游戏贪吃蛇 游戏中要包含以下功能&#xff1a; 1. 贪吃蛇地图绘制 2. 贪吃蛇上下左右移动和吃食物 3. 蛇撞墙&#xff0c;或撞到自身死亡 4. 计算得分 5. 蛇身加速、减速 6. 暂停游戏 2. Win32 API 介绍 Windows是一种多…

【Jenkins】配置及使用|参数化|邮件|源码|报表|乱码

目录 一、Jenkins 二、Jenkins环境搭建 1、下载所需的软件包 2、部署步骤 3、其他 三、Jenkins全局设置 &#xff08;一&#xff09;Manage Jenkins——Tools系统管理->全局工具配置分别配置JDK、Maven、Allure、Git&#xff0c;可以配置路径或者直接选择版本安装 1…