多路查找树(2-3树、2-3-4树、B树)

多路查找树

       其每一个结点的孩子数可以多于两个,且每一个结点处可以存储多个元素。由于它是查找树,所有元素之间存在某种特定的排序关系。在这里,每一个结点可以存储多少个元素,以及它的孩子数的多少是非常关键的。为此我们讲解它4种特殊形式:2-3树、2-3-4树、B树和B+树。

2-3 树

(1)2-3 树是这样的一颗多路查找树:其中的每一个结点都具有两个孩子(我们称它为2结点)或三                                                          个孩子(我们称它为3结点)

(2)一个2结点包含一个元素和两个孩子(或没有孩子),且与二叉排序树类似,左子树包含的元素小于该元素,右子树包含             的元素大于该元素。不过,与二叉排序树不同的是,这个2结点要么没有孩子,要有就有两个,不能只有一个孩子。

(3)一个3结点包含一小一大两个元素和三个孩子(或没有孩子),一个3结点要么没有孩子,要么具有3个孩子。如果某个3结点           有孩子的话,左子树包含小于较小元素的元素,右子树包含大于较大元素的元素,中间子树包含介于两元素之间的元素。

(4)所有的叶子节点必须在同一层次。

 

2-3树复杂的地方就在于新结点的插入和已有结点的删除。毕竟,每个结点可能是2结点也可能是3结点,要保证所有叶子都在同一层次,是需要进行一番复杂操作的。2-3树如下图:

                     

 

2-3树的插入

    

2-3树的插入实现对于2-3树的插入来说,与二叉排序树相同,插入操作一定是发生在叶子结点上。可与二叉排序树不同的是,2-3树插入一个元素的过程有可能会对该树的其余结构产生连锁反应。

2-3树插入可分为三种情况。

第一种:对于空树,插入一个2结点即可,这很容易理解。

第二种:插入结点到一个2结点的叶子上。应该说,由于其本身就只有一个元素,所以只需要将其升级为3结点即可。如下图所示。我们希望从左图的2-3树中插入元素3,根据遍历可知,3比8小、比4小,于是就只能考虑插入到叶子结点1所在的位置,因此很自然的想法就是将此结点变成一个3结点,即右图这样完成插入操作。当然,要视插入的元素与当前叶子结点的元素比较大小后,决定谁在左谁在右。例如,若插入的是0,则此结点就是“0”在左“1”在右了。

                   

第三种:要往3结点中插入一个新元素。因为3结点本身已经是2-3树的结点最大容量(已经有两个元素),因此就需要将其拆分,且将树中两元素或插入元素的三者中选择其一向上移动一层。复杂的情况也正在于此。第一种情况,见下图,需要向左图中插入元素5。经过遍历可得到元素5比8小比4大,因此它应该是需要插入在拥有6、7元素的3结点位置。问题就在于,6和7结点已经是3结点,不能再加。此时发现它的双亲结点4是个2结点,因此考虑让它升级为3结点,这样它就得有三个孩子,于是就想到,将6、7结点拆分,6与4结成3结点,将5成为它的中间孩子,将7成为它的右孩子,如下图的右图所示。

                                

另一种情况,如下图所示,需要向左图中插入元素11。经过遍历可得到元素11比12、14小比9、10大,因此它应该是需要插入在拥有9、10元素的3结点位置。同样道理,9和10结点不能再增加结点。此时发现它的双亲结点12、14也是一个3结点,也不能再插入元素了。再往上看,12、14结点的双亲,结点8是个2结点。于是就想到,将9、10拆分,12、14也拆分,让根结点8升级为3结点,最终形成如下图的右图样子。

                                  

再来看个例子,如图所示,需要在左图中插入元素2。经过遍历可得到元素2比4小、6比1大,因此它应该是需要插入在拥有1、3元素的3结点位置。与上例一样,你会发现,1、3结点,4、6结点都是3结点,都不能再插入元素了,再往上看,8、12结点还是一个3结点,那就意味着,当前我们的树结构是三层已经不能满足当前结点增加的需要了。于是将1、3拆分,4、6拆分,连根结点8、12也拆分,最终形成如下图的右图样子。

                                   

如果2-3树插入的传播效应导致了根结点的拆分,则树的高度就会增加

2-3树的删除

下面例举一下几种情况:

第一种、所删除元素位于一个3结点的叶子结点上,这非常简单,只需要在该结点处删除该元素即可,不会影响到整棵树的其他结点结构。如图所示,删除元素9,只需要将此结点改成只有元素10的2结点

                                   

第二种:所删除的元素位于一个2结点上,即要删除的是一个只有一个元素的结点。如果按照以前树的理解,删除即可,可现在的2-3树的定义告诉我们这样做是不可以的。如图所示,如果我们删除了结点1,那么结点4本来是一个2结点(它拥有两个孩子),此时它就不满足定义了。

                                         

因此,对于删除叶子是2结点的情况,我们需要分四种情形来处理。

情形一,此结点的双亲也是2结点,且拥有一个3结点的右孩子。如图所示,删除结点1,那么只需要左旋,即6成为双亲,4成为6的左孩子,7是6的右孩子。

 

                           

情形二,此结点的双亲是2结点,它的右孩子也是2结点。如图所示,此时删除结点4,如果直接左旋会造成没有右孩子,因此需要对整棵树变形,办法就是,我们目标是让结点7变成3结点,那就得让比7稍大的元素8下来,随即就得让比元素8稍大的元素9补充结点8的位置,于是就有了图的中间图,于是再用左旋的方式,变成右图结果。

                         

 

情形三,此结点的双亲是一个3结点。如下图所示,此时删除结点10,意味着双亲12、14这个结点不能成为3结点了,于是将此结点拆分,并将12与13合并成为左孩子。

                            

 

情形四,如果当前树是一个满二叉树的情况,此时删除任何一个叶子都会使得整棵树不能满足2-3树的定义。如下图所示,删除叶子结点8时(其实删除任何一个结点都一样),就不得不考虑要将2-3的层数减少,办法是将8的双亲和其左子树6合并为一3个结点,再将14与9合并为3结点,最后成为右图的样子。

                                 

第三种:所删除的元素位于非叶子的分支结点。此时我们通常是将树按中序遍历后得到此元素的前驱或后继元素,考虑让它们来补位即可。如果我们要删除的分支结点是2结点。如图所示我们要删除4结点,分析后得到它的前驱是1后继是6,显然,由于6、7是3结点,只需要用6来补位即可,如图右图所示。

                                    

如果我们要删除的分支结点是3结点的某一元素,如图所示我们要删除12、14结点的12,此时,经过分析,显然应该是将是3结点的左孩子的10上升到删除位置合适。

                                

2-3-4 树

2-3-4树其实就是2-3树概念扩充,包括了4结点的使用。一个4结点包含小中大三个元素和四个孩子(或没有孩子),一个4结点要么没有孩子,要么具有4个孩子。如果某个4结点有孩子的话,左子树包含小于最小元素的元素;第二子树包含大于最小元素,小于第二元素的元素;第三子树包含大于第二元素,小于最大元素的元素;右子树包含大于最大元素的元素。一个数组为{7,1,2,5,6,9,8,4,3}的2-3-4树的过程:

                               

下面是对一个2-3-4树的删除结点的演变过程,删除顺序是1、6、3、4、5、2、9

B树

B树是一种平衡的多路查找树,2-3树和2-3-4树都是B树的特例。结点最大的孩子数目称为B树的,因此,2-3树是3阶B树,2-3-4树是4阶B树。一个m阶的B树具有如下属性:

(1)如果根结点不是叶结点,则其至少有两棵子树。

(2)每一个非根的分支结点都有k-1个元素和k个孩子,其中。

(3)每一个叶子结点n都有k-1个元素,其中。

(4)所有叶子结点都位于同一层次。

所有分支结点包含下列信息数据(n,A0,K1,A1,K2,A2,...,Kn,An),其中:Ki(i=1,2,...,n)为关键字,且Ki<Ki+1(i=1,2,...,n-1);Ai(i=0,2,...,n)为指向子树根结点的指针,且指针Ai-1所指子树中所有结点的关键字均小于Ki(i=1,2,...,n),An所指子树中所有结点的关键字均大于Kn,n(<=n<=m-1)为关键字的个数(或n+1为子树的个数)。例如,在讲2-3-4树时插入9个数后的图转成B树示意就如下图的右图所示。左侧灰色方块表示当前结点的元素个数

 

                             

 

在B树上查找的过程是一个顺指针查找结点和在结点中查找关键字的交叉过程。比方说,我们要查找数字7,首先取得到根结点3、5、8三个元素,发现7不在当中,但在5和8之间,因此就通过A2再找到6、7结点,查找到所要的元素。

至于B树的插入和删除,方式是与2-3树和2-3-4树相类似的,只不过阶数可能会很大而已

  

对于n个关键字的m阶B树,最坏情况是要查找几次呢?

第一层至少有1个结点,第二层至少有2个结点,

由于除根结点外每个分支结点至少有|m/2|棵子树,

则第三层至少有2×|m/2|个结点,……,这样第k+1层至少有2×(|

m/2|)k-1

个结点,而实际上,k+1层的结点就是叶子结点。

若m阶B树有n个关键字,那么当你找到了叶子结点,

其实也就等于查找不成功的结点为n+1,因此n+1≥2×(|m/2|)k-1

,即:

也就是说,在含有n个关键字的B树上查找时,从根结点到关键字结点的路径上涉及的结点数不超过log|m/2|((n+1)/2)可没排名额 上春晚是对对方的 +1。

 

B+树

 

                                            

B+树是应文件系统所需而出的一种B树的变型树。一棵m阶的B+树和m阶的B树的差异在于:

1、有n棵子树的结点中含有n个关键字,每个关键字不保存数据,只用来索引,所有数据都保存在叶子节点。

2、所有的叶子结点中包含了全部关键字的信息,及指向含这些关键字记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

3、所有的非终端结点可以看成是索引部分,结点中仅含其子树(根结点)中的最大(或最小)关键字。

通常在B+树上有两个头指针,一个指向根结点,一个指向关键字最小的叶子结点。、、

 

这样的数据结构最大的好处就在于,如果是随机查找,我们就从根节点出发,与B树的查找方式相同。只不过即使在分支节点找到了待查找的关键字。它只是用来索引的。而不能提供实际记录访问。还是需要到达包含此关键字的终端节点(也就是叶子节点)

如果我们需要从最小关键字进行从小到大的顺序查找。我们就可以从最左侧的叶子节点出发。不经过分支节点,而是沿着指向下一个叶子结点的指针就可以遍历所有的关键字。

B+树的数据结构特别适合带有范围的查找。比如查找我们学习 18 ~ 22岁的学生人数,我们可以通过从根节点出发找到第一个 18岁 的学生,然后再在叶子节点按顺序查找到符合范围的所有记录。

B+树的插入、删除过程也和B树类似、只不过插入和删除的元素都是叶子结点上进行而已。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值