数据结构和算法学习笔记十五:多路查找树(B树)
一.概念
1.多路查找树(multi-way search tree):所谓多路,即是指每个节点中存储的数据可以是多个,每个节点的子节点数也可以多于两个.使用多路查找树的意义在于有效降低树的深度,从而降低查找深度.
2.2-3树:2-3树是指满足以下条件的多路查找树:1)每个节点可以是2节点(包含一个元素和2个子节点)或者3节点(包含两个元素和3个子节点);2)一个2节点要么没有子节点,要么有两个子节点,不存在只有一个子节点的情况;3)一个3节点同理,要么没有子节点,要么有3个子节点,且3节点的元素必须是两个.
3.2-3-4树:相对于2-3树,还拓展了4节点(有3个元素和4个子节点),4节点同样需要满足条件:要么没有子节点,要么有4个子节点,其中的元素必须是3个.
4.B树:这是一种平衡的多路查找树,2-3树和2-3-4树都是特殊的B树,其中最多子节点的节点的子节点数称为B树的阶.
5.B+树:对B树的优化,在B+树中每个叶子节点还会记录下一个叶子节点的指针.B+树对B树的查找进行了优化,特别适合带有范围的查找,且插入和删除都必须在叶子节点上进行.
二.2-3树
1.2-3树的存储规则
1)我们以一个实际的2-3树为例,如下图所示:
我们可以看到,在这颗树中根节点8元素节点是2节点,2节点要么没有子树要么有两颗子树,2节点的存储方法和普通的二叉排序树相同,左子树中节点值都比当前节点的值小,右子树中的节点的值都比当前节点值要大;值得注意的是3节点,如图中的12\14元素节点,3节点要么没有子树,要么有3颗子树,且有3颗子树时同样要满足二叉排序树的定义,也就是说左子树中的节点值都比3节点中的最小值小(图中9\10的值比12小),中子树的所有节点的值都介于3节点中的两个值之间(图中13介于12和14之间),右子树中节点的值都比3节点中最大值要大(图中15比14大).最后需要注意,图中的所有叶子节点都在同一层,这也是2-3树存储时需要满足的规则.
借助上图我们直观梳理了2-3树的存储规则,那么接下来我们看一下如何向2-3树中添加元素.
2.二叉树的插入
情况一:我们插入元素3,首先和根节点8比较,3比8小,向8的左子树插入,--->3比4小,向4的左子树插入,--->下面一个节点是一个叶子结点同时也是一个2节点,需要比较吗?显然不需要,因为如果将3元素节点作为1元素节点的子节点,不仅1节点只有一个子节点,不满足定义,而且所有叶子节点也不都在同一层,同样不满足定义.当插入时遇到叶子节点同时这个节点是2节点时,直接将这个2节点变为3节点即可,插入结果如下图所示:
情况二:我们继续再插入一个元素5,首先和8比较,5比8小,向8的左子树插入,--->5比4大,向4的右子树插入,--->插入到6\7元素节点中时出现了问题,这是一个3节点,无法插入,但是也不能将5作为6\7元素节点的子节点,原因自不用赘述,那么应该怎么办呢?我们可以这样做,先不管这是一个3节点,自顾自地将5插入其中,结果如下图所示:
插入后的5\6\7元素节点显然是不符合定义的,3个元素多了,我们需要拿出一个元素来形成一个新的节点,而且这个节点不能向下插入,怎么办呢?相信聪明的你已经想到了,向下不可以我们向上挪一个元素,4元素节点是一个2节点,多一个元素变成3节点也是可以的.但是这里又有了其他问题:哪个元素可以向上挪呢?4元素节点这个2节点变成3节点后需要有3颗子树,但是现在只有两颗子树,怎么办呢?第二个问题不难解决,现在的5\6\7元素节点有3个元素,挪动一个上去后将剩下的两个元素拆开,形成两个2节点即可,所以第一个问题也就解决了,一定是挪动5\6\7元素节点里面中间的元素6上去,因为3元素节点的中子树的所有元素值都要介于这个节点的两个值之间,不信的话你可以挪动5或7上去试一试.好了,现在我们经过对2-3树中部分节点的元素相互移动和节点拆分合并,成功将元素5插入了,结果如下图所示:
总结一下这次插入操作:元素插入时一定是插入叶子结点中的,当即将插入的节点是一个2节点时,直接插入即可,当要插入的节点是一个3节点时,先不管不顾地插入,然后将插入后节点的3个元素中中间的元素向上挪动,并将剩下的两个元素拆分成两个节点.
诶,是不是又有问题了,如果挪上去发现上面的节点还是3节点怎么办呢?我们来看下面一个例子:
情况三:插入元素11,显然经过比较(省略比较过程)应当插入9\10元素节点中,先插入,如下图所示:
接下来按照上一次的步骤我们将9\10\11这三个元素中中间的10元素向上挪,并将剩下的元素9和11拆开,结果如下图所示:
我们会发现,元素10挪上去时原来的12\14元素节点本来就是3节点,现在有3个元素了,然后将元素9和元素11拆开形成两个节点后,这个10\12\14节点就有4个子节点了(本来就有3个,又拆出来一个),那么接下来怎么办?还用问么,继续向上挪呗!将10/12/14这三个元素中的中间元素12继续向上挪,并将剩下的10和14拆开,就形成了两个2节点,诶,不是刚好有4个子节点吗?一切都是那么完美.继续挪动后形成了如下图所示的2-3树,11元素的插入就算完成了:
总结:如果你一直跟着我的思路读到这里的话,相信你已经发现了一些规律了.当我们向2-3树中插入元素时,一定是向叶子节点中插入的.如果这个叶子节点是2节点,直接插入将其变为3节点即可.如果这个叶子节点已经是3节点了,先插入,然后将3个元素中中间的元素挪给父节点并将剩下的两个元素拆分成两个节点,如果父节点是2节点的话,父节点就会变成3节点,如果父节点已经是3节点的话,同样先将挪上去的元素放入,然后将3个元素中中间的元素继续向父节点挪动并将剩下的两个元素拆分为两个节点,这个父节点刚好有4个子节点就可以分配给这两个2节点了...如果父节点的父节点还是3节点的话,不用说,继续向上挪动元素,直到遇到某个父节点是2节点停止或者到达根节点.很自然地我们会想到,如果一直挪到根节点并且根节点也刚好是3节点呢?有兴趣的话可以继续将元素2插入上图中的2-3树中试一试,就会出现这种情况.其实不难解决,如果将元素放入根节点中并将根节点此时的3个元素的中间元素向上挪动形成新的根节点,将剩下的两个元素拆分为两个节点刚好可以作为新根节点的子节点.其实这就是2-3树的深度增长的情况了.从这里可以看出来,2-3树的深度的增长不是向下增长的,而是向上增长的.
总的来说,2-3树的插入方法可以用一个"挤"字总结,插入时直接插入节点中,如果节点中的元素个数达到3个,挤不下了,就将中间的元素向上挤并将剩下两个元素拆成两个节点,如果上一层的节点还挤不下,继续向上挤并将剩下的元素拆分......
3.2-3树的删除实现
2-3树的删除有很多形式,我们可以看一看下面的例子总结如何进行删除:
情况一:删除下面2-3树中的节点6
我们可以发现,将6删除后4\6元素节点由3节点变成了2节点,那么子节点的个数必须减少1,我们很容易想到可以将5元素节点和7元素节点合并,结果如下图:
情况二:删除下面2-3树中的元素40:
显然,删除元素40后,原来的20\40元素节点由3节点变成了2节点,所以它的子节点的数目应该减少1,但是这里子节点都是3节点,显然不能合并,那么我们应该怎么办呢?我们可以从子节点中匀一个元素给这个节点,显然,只能匀35上去,匀完后就有了如下图的结果:
总结:我们可以在这里作一个小总结.将情况一和情况二对比,我们发现同样是3节点的一个元素被删除,情况一删除后变成了2节点,而情况二中删除后这个节点还是3节点,这是怎么回事呢?其实情况一也可以在移除完成后仍然是3节点的(读者可自行尝试看情况一能否保留3节点).这里我们用一个"借"字来总结这个移除过程:当某个元素被移除后,这个元素的位置就出现了一个空缺,那么如何去补这个空缺呢?我们可以通过借用子节点中的元素的方式来补,优先借用这个元素的相邻子节点中的元素,如情况一中的元素5和元素7,但是显然这两个元素都分别在2节点中,元素离开了这个节点就消失了,所以借不了,我们就考虑不借了,将剩下的元素合并保留4节点为2节点的形式;情况二中20\40元素节点中的元素40被移除,由于3个子节点都是3节点,所以直接借了子节点中的元素来用,当然如果子节点还有子节点,还需要继续借用元素来填补被借的元素位置或者合并元素.
那么,如果我们遇到子节点的元素借不出去又合并不了的情况怎么处理呢?
情况三:移除下面2-3图中的元素90:
显然,90元素所在节点是2节点,90元素移除后这个节点就没有元素了,必须从其他地方借用一个元素来填补或者合并节点.如果将85元素节点和95元素节点合并显然不是很合适,因为合并后将其作为80元素节点的右子节点就不满足2-3树的定义了,但是从85元素或者95元素中借用一个元素填补90元素的位置还是不满足2-3树定义.怎么办呢?是不是又想到了,子节点借不了向父节点借嘛,将80元素借用过来,然后80元素留下的空位再从它的左子树中借用一个元素来填补,首先考虑左子树中的最大元素43,这个元素被借用后又出现了空位,然后可以考虑将其父节点中的35元素借用过来填补空位,之后父元素留下的空位让25元素和35元素合并即可.结果如下图所示:
总结:我们可以看到,当一个元素被移除后,这个元素留下的空位我们可以采用借的方式来填补,首先从左右子树中去借,从子树中借一定借用的是左子树的最大元素或者右子树的最小元素.如果子树中没有元素可借,那么可以考虑合并子节点(子节点是叶子节点的话).当一个元素被借用来填补其他元素的位置,那么这个元素也可以采用同样的方案从它的子树中或者父节点中去借用元素,也可以考虑合并子节点.如果最终发现不能借用了(这种情况出现时,一定是借用了完全二叉树中的节点),这时就要考虑将树的深度降低1了(这里不再赘述如何降低树的深度).
三.2-3-4树
对于2-3-4树,这里可以不再赘述,因为2-3-4树就是2-3树的进一步拓展,其添加元素或者删除元素的过程和2-3树相同.
四.B树:
B树是平衡的多路查找树,2-3树和2-3-4树都是B树的特例.
五.B+树:
我们在说到2-3树时有讲到在2-3树中所有叶子节点都在同一层,这也是所有B树都需要满足的条件.如果我们在这些叶子节点中增加两个指针,指向父节点中的相应元素及下一个兄弟节点的位置,那么这样的树就是B+树.B+树特别适合有范围的查找(根据叶子结点中下一个叶子节点的指针遍历所有叶子节点,根据父节点的指针判断范围).
数据结构和算法学习笔记十五:多路查找树(B树)的更多相关文章
- python3.4学习笔记(十五) 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)
python3.4学习笔记(十五) 字符串操作(string替换.删除.截取.复制.连接.比较.查找.包含.大小写转换.分割等) python print 不换行(在后面加上,end=''),prin ...
- (转载)西门子PLC学习笔记十五-(数据块及数据访问方式)
一.数据块 数据块是在S7 CPU的存储器中定义的,用户可以定义多了数据块,但是CPU对数据块数量及数据总量是有限制的. 数据块与临时数据不同,当逻辑块执行结束或数据块关闭,数据块中的数据是会保留住的 ...
- (C/C++学习笔记) 十五. 构造数据类型
十五. 构造数据类型 ● 构造数据类型概念 Structured data types 构造数据类型 结构体(structure), 联合体/共用体 (union), 枚举类型(enumeration ...
- java数据结构和算法学习笔记
第一章 什么是数据结构和算法 数据结构的概述 数据结构是指 数据再计算机内存空间或磁盘空间中的组织形式 1.数据结构的特性 数据结构 优点 缺点 数组 插入快,如果知道下标可以快速存取 查找和删除慢 ...
- javascript 数据结构和算法读书笔记 > 第五章 队列
队列是一种列表,但是它只能够在队尾插入元素,在队首删除元素.队列用于存储按照顺序排列的数据,先进先出.而栈则是后入栈的元素反而被优先处理. 实际中一般被应用在进程池.排队操作上面. 1. 队列的操作 ...
- Java基础学习笔记十五 集合、迭代器、泛型
Collection 集合,集合是java中提供的一种容器,可以用来存储多个数据. 在前面的学习中,我们知道数据多了,可以使用数组存放或者使用ArrayList集合进行存放数据.那么,集合和数组既然都 ...
- MySQL学习笔记十五:优化(2)
一.数据库性能评测关键指标 1.IOPS:每秒处理的IO请求次数,这跟磁盘硬件相关,DBA不能左右,但推荐使用SSD. 2.QPS:每秒查询次数,可以使用show status或mysqladmin ...
- angular学习笔记(十五)-module里的'服务'
本篇介绍angular中的模块:module 在笔记(二)http://www.cnblogs.com/liulangmao/p/3711047.html里已经讲到过模块,这篇主要讲模块的 '服务' ...
- Java学习笔记十五:Java中的成员变量和局部变量
Java中的成员变量和局部变量 一:成员变量: 成员变量在类中定义,用来描述对象将要有什么 成员变量可以被本类的方法使用,也可以被其他类的方法使用,成员变量的作用域在整个类内部都是可见的 二:局部变量 ...
随机推荐
- 循序渐进BootstrapVue,开发公司门户网站(5)--- 使用实际数据接口代替本地Mock数据
在我们开发一些门户网站功能的时候,有时候我们需要快速的创建数据模型来进行数据展示,因为数据结构可能处于不断的修正变化之中,因此服务端的接口我们可以暂时不开发,当我们基本完成数据结构和界面展示的时候,就 ...
- excel VBA数组运用
Sub a()Dim i人数 As Integer'定义变量Dim i考试成绩() As Integer'定义数组Dim i As Integer'定义变量i人数 = InputBox("输 ...
- 腾讯云TKE-基于 Cilium 统一混合云容器网络(下)
前言 在 腾讯云TKE - 基于 Cilium 统一混合云容器网络(上) 中,我们介绍 TKE 混合云的跨平面网络互通方案和 TKE 混合云 Overlay 网络方案.公有云 TKE 集群添加第三方 ...
- UI自动化学习笔记- Selenium元素等待(强制等待、显示等待、隐式等待)
一.元素等待 1. 元素等待 1.1 什么是元素等待 概念:在定位页面元素时如果未找到,会在指定时间内一直等待的过程 意思就是:等待指定元素已被加载出来之后,我们才去定位该元素,就不会出现定位失败的现 ...
- hdu 2159 二维完全背包
Problem Description 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务.久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级.现 ...
- [源码解析] 深度学习分布式训练框架 horovod (13) --- 弹性训练之 Driver
[源码解析] 深度学习分布式训练框架 horovod (13) --- 弹性训练之 Driver 目录 [源码解析] 深度学习分布式训练框架 horovod (13) --- 弹性训练之 Driver ...
- MySql:使用Navicat定时备份数据库
Navicat自带就有备份 还可以直接计划任务,很方便. 1. 新建计划 打开navicat客户端,连上mysql后,双击左边你想要备份的数据库.点击"计划",再点击" ...
- 资源:Hadoop安装包下载路径
下载路径 Hadoop所有版本:http://archive.apache.org/dist/hadoop/common/
- 嵌入式Linux会议LinuxCon欧洲的时间表公布
From: http://linuxgizmos.com/embedded-linux-conference-and-linuxcon-europe-schedules-posted/ Linux基金 ...
- docker起不来报错:Failed to start Docker Application Container Engine.
报错信息如下: [root@localhost localdisk]# systemctl restart docker Job for docker.service failed because t ...