B树的查找
那就开始吧!
举个栗子,我先画几张图,让大家体验一下它的查找方式。然后,开始上代码解释。好吗?
就以上面的为例,现在,我们要依次查找如下几个键值,请记牢12 8 17
三个键值。那就按部就班进行。
No.1 首先要找键值为:12
上来,就找到了。因为12
这个键值正好处于B树的临时根节点。由此可见,查找键值是从B树的根节点进行的。
No.2 接着查找8
:
看着很简单,对吧?聪明的你应该不这么觉得。那就一起分析一下上图吧
首先,红色的箭头即findNode
是在tempRootNode
对吧,相信你还记得B树的结构。
如果B树的结构还不知道的读者,或者之前没有了解过B树的结构,亦或者没看过其他博主写过相关B树的文章,可以在我的主页->博客分类->数据结构算法里面。进行查找哦。
那先要做什么呢?是不是先看一下当前findNode
所指向的节点是否有我们想要找的键值,对的。这一找,啥也没有。该咋办呢?还有它的孩子,但此刻的findNode
该怎么找呢?不会随便指个位置,就开始找吧。当然不是,这时候,会借助要查找的键值与findNode
里面的键值关系对吧?发现8<12
,然后就应该返回对应的孩子,继续走下去对吧?没错。此时,findNode
来到了6 9
的节点,继续查找键值,如果键值没有,就开始找合适的孩子进行遍历。
概括一下:
- 在查找键值的时候,总是在B树的临时根节点进行查找;
- 如果根节点没有要找的键值,就要遍历合适的孩子进行查找;
- 直到找到目标键值为止,如果没有找到,就返回空
看了上面的概括,我现在有点饿了,你自己看看17是如何查找的?
ok,接下来进入B树查找的代码讲解:
这里先声明一下,一般查找到节点都是要曝光的,而且在后面的删除节点都是需要先经过查找,我B树的struct
在class里面,所有,要在public属性里面准备一个指针,好用来接受这个已经查找到节点。(当然,如果结构不这么设计,就不会这样啦)。
my_B_tree* find(const size_t& findValue)//查找的键值。
{
return _find(findValue, tempRootNode);//findValue 目标查找的键值;tempRootNode B树的临时根节点
}
_find函数内容是查找目标键值的主干,该函数体中的函数,会在下面一一奉上!
if (root)
{
int pos = binarySearch(root->key, findValue, 0, root->degress);
if (pos != -1)
return root;
else
{
Insert_Location location = indexSelection(root, findValue);
switch (location)
{
case Insert_Location::_first:
{
my_B_tree* okNode = nullptr;
okNode = _find(findValue, root->sonPt[(int)location]);
return okNode;
}
case Insert_Location::_second:
{
my_B_tree* okNode = nullptr;
okNode = _find(findValue, root->sonPt[(int)location]);
return okNode;
}
case Insert_Location::_third:
{
my_B_tree* okNode = nullptr;
okNode = _find(findValue, root->sonPt[(int)location]);
return okNode;
}
}
}
}
return nullptr;
先来在这里解释一下基本逻辑,相信大家不难看到,这个函数是一个递归。且听我来分析:
还是文章首部画的那张图吧,这次寻找19
。
先仔细看一下上面的图,从根节点开始找19。这个函数又是一个递归,那它就不能缺少递归的条件,否则就会函数栈boom!所以右图的意思是这样的,12的节点进入函数中,先判断该节点是否为空?如果不为空,就使用二分查找来搜索是否有19这个键值,结果:没有,那就搜索路径,然后走合适的路径进入到17。……来到了19的节点,这个时候发现二分查找搜索找到了目标键:19.返回此节点的地址。该递归函数return出函数栈,此时回到了函数之前所调用它的递归函数的位置,然后继续return,直到把这个目标所在节点返回出来。这里,我要提醒一下,一定要在最后加return nullptr;
如果不加,这个函数没有找到的话,就会返回一个野指针。
binarySearch函数是一个二分查找算法,考虑到B树的多阶性,所以这里使用了效率较高的二分查找来进行查找是否在当前节点。如果是就返回index,否则返回-1.
int midIndex;
while (leftIndex <= rightIndex)
{
midIndex = ((rightIndex-leftIndex) >> 1)+leftIndex;
if (findValue == arr[midIndex])
return midIndex;
if (findValue < arr[midIndex])
rightIndex = midIndex-1;
else if (findValue > arr[midIndex])
leftIndex = midIndex+1;
}
return -1;
indexSelection函数作用:当目标键值不在当前节点中,就继续往下一层选择合适的孩子寻找。
size_t i = 0;
//分裂后,根节点关键字个数为1的情况
for (; i < curNode->degress; ++i)
{
if (key <= curNode->key[i])
{
//如果满足条件,就根据当前的索引i值,返回指定的指针进行插入
return (Insert_Location)i;
}
//否则就继续循环
}
return (Insert_Location)(i);
感谢各位的阅读, 如果有更好的优化,请在下方评论留言,我会认真的考虑各位的建议。B树的删除,博主还未实现,且听下回对B树删除的分析。谢谢大家!