咬文嚼图式的介绍二叉树、B树/B-树
前言
因为本人天资愚钝,所以总喜欢将抽象化的事务具象化表达。对于各类眼花缭乱的树,只需要认知到它们只是一种数据结构,类似数组,切片,列表,映射等这些耳熟能详的词汇。对于一个数据结构而言,无非就是增删改查而已,既然各类树也是数据结构,它们就不能逃离增删改查的桎梏。
那么,为什么我们需要树这种数据结构呢,直接用数组不行吗,用切片不行吗?当然可以,只不过现实世界是缤纷杂乱的,而又没有一种万能药式的数据结构以应对千变万化的业务需求。所以,才会有各类树,而且一些“高级”数据结构是基于树形数据结构的,例如映射。
二叉树
在中文语境中,节点结点傻傻分不清楚,故后文以 node 代表 "结点",root node 代表根节点,child node 代表 “子节点”
二叉树是诸多树状结构的始祖,至于为什么不是三叉树,四叉树,或许是因为计算机只能数到二吧,哈哈,开个玩笑。二叉树很简单,每个 node 最多存在两个 child node,第一个节点称之为 root node。
二叉树具备着一些基本的数学性质,不过很简单,定义从 i
从 0 开始:
- 第
i
层至多有2i
个 node; - 深度为 i 层二叉树至多有
2i+1-1
个 node。
二叉树的特殊类型
这里有兴趣的可以了解一下,不影响后文的阅读。二叉树根据 child node 的不同,衍生出了几种特殊类型:在一颗二叉树中,如果每个 node 都有 0 或 2 个 child node,则二叉树是满二叉树;定义从 i
从 0 开始,一棵深度为 i
,且仅有 2i+1−1
个 node 的二叉树,称为完美二叉树;若除最后一层外的其余层都是满的,并且最后一层要么是满的,要么在右边缺少连续若干 node,则此二叉树为完全二叉树。
二叉搜索树
二叉搜索树(Binary Search Tree),也叫二叉查找树,有序二叉树,排序二叉树(名字还挺多)。它是一种常用且特殊的二叉树,它具备一个特有的性质,left node(左结点)始终小于 parent node (父结点),right node 始终大于 parent node。
二叉搜索树的查找
- 二叉搜索树从 root node 开始,如果命中则返回;
- 否则,目标值比 node 小进入 left node;
- 比 node 大进入 right node;
- 如果左右都为空,则未命中。
二叉搜索树的遍历
二叉搜索树有不同的遍历方式,这里介绍常用的中序遍历方式:
- 先遍历左子树;
- 然后查找当前左子树的 parent node;
- 遍历右子树。
二叉搜索树的插入
- 二叉搜索树从 root node 开始,如果命中则不进行操作;
- 否则,目标值比 node 小进入 left node;
- 比 node 大进入 right node;
- 最终将值插入搜索停止的地方。
二叉搜索树的删除
二叉树的删除和查询基本一致,只要在命中时删除即可。
- 二叉搜索树从 root node 开始,如果命中则删除;
- 否则,目标值比 node 小进入 left node;
- 比 node 大进入 right node;
- 删除后使用该 node 左子树最大值或者右子树最小值替代该 node。
自平衡二叉树
从上面的几张动图中我们知晓,二叉搜索树不同于线性结构,它可以大大降低查找,插入的时间复杂度。但在特殊情况下,二叉搜索树可能退化为线性结构,假如我们依次插入1,2,3,4,5:
此时,二叉搜索树退化为线性结构,效率重新变回遍历。于是,便出现了自平衡二叉树,例如 AVL 树,红黑树,替罪羊树等。但它们并不是本文重点,下面我要介绍的是另外一种很常见的自平衡二叉树:B树。
B树
B树和B-树是同一个概念。B树相对于二叉树有两点最大的不同:
- 每个 node 可以有不止一个数值
- 每个 node 也可以有不止两个 child node
B树有两种类型 node:
- internal node(内部结点):不仅仅存储数据,也具备 child node;
- leaf node(叶子结点):仅存储数据,不具备 child node。
这两种 node 不同于前文所提的 root node 和 child node。root 和 child 是相对于阶层的概念,而 internal 和 leaf 是相对于性质的概念
一个简单的图例如下:
图中的蓝色方块是 internal node,绿色则是 leaf node。
B树有一些需要满足的性质,这里的抽象的逻辑有些烧脑,我会对照前面的图片来解释。设定一颗 m 阶的B树,m = 3
:
设 internal node 的 child node 个数为 k
:
- 如果 internal node 是 root node,那么
k = [2, m]
,比如上图的 8 有两个 child node(3|6, 10/12); - 如果 internal node 不是 root node,那么
k = [m/2, m]
,m/2 向上取整,比如上图的3|6
有三个 child node; - 如果 root node 的
k
为 0,那么 root node 是 leaf 类型的; - 所有 leaf node 在同一层,上图最后一行的六个 node。
设任意 node 键值个数为 n
:
- 对于 internal node,
n = k-1
, 升序排序,满足k[i] < k[i+1]
,比如上图的三个 internal(8,3|6,10|12) 都满足此规律; - 对于 leaf node,
n = [0, m-1]
,同样升序排序,比如上图最后一个的六个 leaf,其键值最多为两个。
上述的概念有些抽象,但是这是理解B树关键的地方所在,后面在B树的插入讲解,会有更多具象的动图来解释这些概念。
B树的查找
B树的查找类似于二叉树:
- 从 root node 开始,如果目标值小于 root node,进入左子树,否则进入右子树;
- 遍历 child node 的多个键值;
- 如果匹配到键值,则返回;
- 如果不匹配,则根据目标值的范围选择对应的子树;
- 重复步骤2、3、4,直到匹配成功返回或者未找到。
假如我们要查找 11:
B树的遍历
B树的遍历方式类似二叉搜索树,不过因为B树一个 node 有多个键值和多个 child node,所以需要遍历每个左右子树和键值:
- 先遍历第一个左子树,也就是 parent node 第一个键值的左边;
- 然后查找当前 parent node 的第一个键值;
- 遍历第二个左子树,也就是 parent node 第二个键值的左边;
- 遍历完搜索的左子树,最后遍历当前 parent 的最右子树,即最后一个键值的右边。
B树的插入
插入前面的过程和查询一致,在插入后可能需要重整 node,以符合B树的性质,例如插入 16:
- 先查找到目标 node,也就是
13|15
; - 因为这是一颗 3 阶B树,所以 node 最多只能有两个键值,于是向上传递中间值 15;
- parent node 最多也只能有两个键值,于是继续向上传递中间值 12;
- 此时 root node 是 8|12,需要有三个 child node,于是 10|15 需要拆分,再向下进一步调整,至此,插入 16 完成。
B树的删除
删除是插入的逆操作,但是往往比插入更复杂,因为删除后经常需要重整 node:
- 先查找到目标 node,也就是
16
; - 删除 16,此时 15 child node 剩下一个,不符合条件,递归向上调整,一直到根节点;
- 直到所有的条件都满足后,删除 16 完成。
咬文嚼图式的介绍二叉树、B树/B-树的更多相关文章
- 四种生成和解析XML文档的方法介绍
解析XML的方法越来越多,但主流的方法也就四种,即:DOM.SAX.JDOM和DOM4J 1.DOM(Document Object Model) DOM是用与平台和语言无关的方式表示XML文档的官方 ...
- Atitit 常见的树形结构 红黑树 二叉树 B树 B+树 Trie树 attilax理解与总结
Atitit 常见的树形结构 红黑树 二叉树 B树 B+树 Trie树 attilax理解与总结 1.1. 树形结构-- 一对多的关系1 1.2. 树的相关术语: 1 1.3. 常见的树形结构 ...
- AC自动机——1 Trie树(字典树)介绍
AC自动机——1 Trie树(字典树)介绍 2013年10月15日 23:56:45 阅读数:2375 之前,我们介绍了Kmp算法,其实,他就是一种单模式匹配.当要检查一篇文章中是否有某些敏感词,这其 ...
- 数据结构(一)二叉树 & avl树 & 红黑树 & B-树 & B+树 & B*树 & R树
参考文档: avl树:http://lib.csdn.net/article/datastructure/9204 avl树:http://blog.csdn.net/javazejian/artic ...
- 剑指offer38:输入一棵二叉树,求该树的深度
1 题目描述 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 2 思路和方法 深度优先搜索,每次得到左右子树当前最大路径,选择 ...
- 数据结构(三) 树和二叉树,以及Huffman树
三.树和二叉树 1.树 2.二叉树 3.遍历二叉树和线索二叉树 4.赫夫曼树及应用 树和二叉树 树状结构是一种常用的非线性结构,元素之间有分支和层次关系,除了树根元素无前驱外,其它元素都有唯一前驱. ...
- 树(二叉树 & 二叉搜索树 & 哈夫曼树 & 字典树)
树:n(n>=0)个节点的有限集.有且只有一个root,子树的个数没有限制但互不相交.结点拥有的子树个数就是该结点的度(Degree).度为0的是叶结点,除根结点和叶结点,其他的是内部结点.结点 ...
- Sandcastle帮助文档生成器使用介绍
一.软件介绍 Sandcastle是一个管理类库的文档编译器,是用于编译发布组件(Assembly)信息的一个工具,这个工具通过反射和Xslt技术,可以从dll文件及其xml注释(命令行编 ...
- IE11新文档模式Edge介绍与评估,及在WebBrowser应用中的使用。
浏览器模式与文档模式概念是怎么来的? 1.浏览器模式与文档模式概念起源 为了解决兼容性的问题,在IE浏览器(IE8, IE9, IE10)中,引入了浏览器模式和文档模式两个概念,浏览网页时可以通过按F ...
- 一文带你详细介绍c++中的std::move函数
前言 在探讨c++11中的Move函数前,先介绍两个概念(左值和右值) 左值和右值 首先区分左值和右值 左值是表达式结束后依然存在的持久对象(代表一个在内存中占有确定位置的对象) 右值是表达式结束时不 ...
随机推荐
- Linux/Golang/glibC系统调用
Linux/Golang/glibC系统调用 本文主要通过分析Linux环境下Golang的系统调用,以此阐明整个流程 有时候涉略过多,反而遭到质疑~,写点文章证明自己实力也好 Golang系统调用 ...
- 异构数据源同步之数据同步 → datax 改造,有点意思
开心一刻 去年在抖音里谈了个少妇,骗了我 9 万 后来我发现了,她怕我报警 她把她表妹介绍给我 然后她表妹又骗了我 7 万 DataX DataX 是什么,有什么用,怎么用 不做介绍,大家自行去官网( ...
- linux 文件的特殊权限:suid sgid sticky
目录 一.关于文件的特殊权限 二.suid 三.SGID 四.Stickybit 一.关于文件的特殊权限 1.文件与目录设置不止基础权限:r,w,x,还有所谓的特殊权限.特殊权限会拥有一些" ...
- Jenkins自动化集成
gitlab连接Jenkins 创建token后 , 现在的网页上就会出现一个token: token只出现一次,注意保存 将这个token在Jenkins上配置,现在开始配置Jenkins Jenk ...
- 抖音越狱版本App下载
一.准备下载越狱版本抖音App 一般下载越狱版本App要不从越狱手机上Crack 正版App,另外一种从PP助手或者越狱市场进行下载,这里选择第二种方式 感谢 http://iosre.com/t/p ...
- git push遇到的问题“Please make sure you have the correct access rights and the repository exists.”
问题:今天在用idea往github推送代码的时候,出现了下面的报错 原因:是ssh key有问题,连接不上服务器 解决: 1.得重新在git设置一下身份的名字和邮箱 git config --glo ...
- C#笔记 picturebox功能实现(滚动放大,拖动)
代码链接 1. picturebox上的坐标与原图中坐标的转换 (1) 由于图片的长宽比例和picturebox的长宽比例不同,所以图片不想拉伸的话,左右或者上下会有留白.将picturebox的si ...
- 使用 INFINI Console 实现 Elasticsearch 的增量数据迁移
功能介绍 # 在 INFINI Console 1.3.0 版本里,数据迁移功能增加了对增量迁移的支持.这篇文章将会介绍增量迁移的具体使用方法和实现原理. 场景介绍 # 以常见的日志场景为例,假设 A ...
- Flashcat与出行科技企业一起实践多云可观测
当前架构 某出行科技企业从单个公有云往多云转型,依托于国内领先的公有云提供商,采用多云架构,在可用性.弹性.成本.供应商依赖方面,拥有了显著的优势. 相应的,多云架构也给技术团队带来了一定的复杂度和技 ...
- FlashDuty Changelog 2023-09-21 | 自定义字段和开发者中心
FlashDuty:一站式告警响应平台,前往此地址免费体验! 自定义字段 FlashDuty 已支持接入大部分常见的告警系统,我们将推送内容中的大部分信息放到了 Lables 进行展示.尽管如此,我们 ...