B树和 B+树

提起B树,不禁想起金庸小说《射雕英雄传》中描述的成吉思汗部队。成吉思汗部队军官名称听起来通俗,却也清楚,叫做十夫长、百夫长、千夫长、万夫长。一个十夫长管理一支10个士兵的部队,一个百夫长管理10个十夫长,因此管理一支100个士兵的部队,如此等等。不管怎样,管理是有效率的。计算机数据也这样管理好了。

现在考虑一点动态的问题。部队打仗发生减员的时候,有十夫长手下的士兵少于一半了,怎么办?这时,可以从同一个百夫长管理的范围内,从邻近的十夫长那里匀一些部队过来,使得每个十夫长手下的士兵仍然至少都大于一半。这样就调整好了。整支部队变动很小。如果两个十夫长都缺人,那么把两支部队合并,其中一个十夫长降为士兵。百夫长因次减少一名十夫长。百夫长的编制处在临界状态时,减少一个使他手下的十夫长少于一半,这时求助他的千夫长。到他的千夫长下面,从邻近的百夫长那里匀一些十夫长队伍过来,使大家仍然保持都多于半数。如果邻近的百夫长那里也处比较短缺状态,那就合并2支百夫长部队,并从千夫长手下减少一名百夫长。匀或者合并,总有一种可以办到,依此类推。这样就调整完了。

在新招扩编的时候。当十夫长的部队已经满员时,把他的部队分成两支,并升级一名十夫长,到他们所属的百夫长那里。这样十夫长就调整好了。如果百夫长已经满员,增加升级的十夫长造成超编,同样分解他的部队,并升级一名百夫长到千夫长那里。以此类推。

把这些十夫长、百夫长队应到节点和键来看,就是B树。

B+和 B树只有一些轻微的不同。B树上层节点对下层节点的管理是开区间管理。下层节点出现的所有键值,严格的说,下层节点出现的所有键值所代表的数据,都在上层节点相邻的两个键之间。而 B+树是半闭半开区间管理。左边的键值继续存在于下层节点最左的位置。这个不同导致了一些微妙的差异。

在存储效率上,B+树多存了一个上层的键值,似乎存储效率略差。但是B+树内部节点不需要存储数据指针,在移动键值时也避免了需要同时维护数据指针的负担。当然,不管B树还是B+树,最终在叶节点上还是每个键值都对应一个数据指针。

在分解与合并问题上,B树分解时,由于有一个键要升级到上层节点去,最后两个下层节点中键的个数比原来少1。比如满的10个键的B树节点,当增加第11个元素时,引起节点分裂,分裂成的两个节点每个都是5个元素。而B+树会变成,一个节点6个元素,一个节点5个元素。合并的时候,B+树直接丢掉了上层的一个键值,而B树还需要把上层的键搬下来存在新节点中间,所以B树合并后会比B+树多一个元素。

在检索效率上,B+树多存了一个键值,会增加比较次数,导致效率下降。表面上看起来是这样。实际上因为位置的固定性,可以跳过第一个元素,所以检索效率没差别。作为一个附加的要求,B+树还要求最终数据通过链表连起来。这样在顺序搜索和从定位点开始的顺序搜索不需要反复穿梭在上下层节点,这样提高了顺序搜索的效率。

在多节关键字的情况下,比如用长字符串做关键字。B+树还可以分节存储关键字,由根到叶子的路径来连接成这个关键字,每节只比较一部分关键字,这样也可以提高比较的效率。

最后,万一遇到索引节点损坏,需要重构B+树时,因为数据和内部节点是分离的,直接把内部节点丢弃重构即可,不用担心会导致数据丢失。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值