例4.22 图4-24所示的B树类似于图4-23,但有重复键值。具体来说:键11已被键13替换;键19、29和31全部被键23替换。这样就造成根结点的键是17而不是13。原因在于,虽然13是第二个子树根结点中最小的键,但它不是该子树的新键,因为它在根结点的第一个子树中出现过。
我们还需要对根结点的第二个子结点做些改变。第二个键改为37,因为它是第三个子结点(从左数第五个叶结点)的第一个新键。最有趣的是,第一个键现在为空,因为第二个子结点(第四个叶结点)根本就没有新键。换言之,如果查找某个键且到达根结点的第二个子结点,我们不会从该子结点的第二个子结点起开始查找。若是查找23或其他更小的值,我们应该从它的第一个子结点起开始查找,在那里我们将找到所需的记录(如果是17),或找到所需的记录的第一个(如果是23)。
注意:
(1)查找13时我们不会到达根结点的第二个子结点,而是直接到第一个子结点中去查找。
(2)如果查找介于24~36之间的某个键,我们会直接到第三个叶结点中查找。但当我们连一个所需键值都找不到时,我们就知道不必继续往右查找。举例来说,如果叶结点中存在键24,它要么在第四个叶结点上,这时根结点的第二个子结点中的空键将会被24替代;要么在第五个叶结点上,这时根结点的第二个子结点的键37将被24替代。
3、B树中的查找
我们现在再回到最初的假定,即叶结点中没有重复键。这个假定可以简化对B树操作的讨论,但该假定对这些操作来说并非必不可少。假设我们有一个B树索引并且想找出查找键值为K的记录。我们从根到叶递归查找,查找过程为:
基础:若处于叶结点,我们就在其键值中查找。若第i个键是K,则第i个指针可让我们找到所需记录。
归纳:若处于某个内部结点,且它的键为K1,K2,,Kn,则依据在4.3.1节中给出的规则来决定下一步该对此结点的哪个子结点进行查找。也就是说,只有一个子结点可使我们找到具有键K的叶结点。如果K
例4.23 假定有一棵如图4-23所示的B树,且我们想找到查找键为40的记录。我们从根结点开始,其中有一个键13。因为13≤40,我们就沿着它的第二个指针来到包含键为23、31和43的第二层结点。
在这个结点中,我们发现31≤40<43,因而我们沿着第三个指针来到包含31、37和40的叶结点,如果数据文件中有键值为40的记录,我们就应该在这个叶结点中找到键40。既然我们没有发现键40,就可以断定在底层的数据块中没有键值为40的记录。
注意,要是查找键为37的记录,我们所做的决定都和上面一样,但当到达叶结点时,我们将找到键37。因为它是叶结点中的第二个键,因此我们沿着第二个指针可以找到键值为37的数据记录。
4、范围查询
B树不仅对搜寻单个查找键的查询很有用,而且对查找键值在某个范围内的查询也很有用。一般来说,范围查询在Where子句中有一个项,该项将查找键与单个值或多个值相比较,可用除“=”和“”之外的其他比较操作符。使用查找键属性K的范围查询例子如下:
select * form R where R.k > 40;
或者
select * form R where R.k > 10 and R.k