查找(四)-------基于B树的查找和所谓的B树
关于B树,不想写太多了,因为花在基于树的查找上的时间已经特么有点多了,就简单写写算了,如果以后有需要,或者有时间,可以再深入写写
首先说一下,为什么要有B树,以及B树是什么,很多数据结构和算法的书上来就上B树的定义,然后讲基于B树的几个操作,什么插入啊,建立啊,分裂啊,最后写个查找算法了事
我想,请问一下,编书的人这样搞是什么意思,这样还不如直接画算法的示意图,接下来是源码就够了,这样学下来,各种查找,搜索算法之间都是孤立开来的,无法领会到他们为什么这样做,他们是怎样想出来的,算了,不扯了,心里烦编书的人
为什么会有B树呢?我们还是先回到二叉排序树和平衡二叉排序树上,有了他们,我们才能理解为什么会有B树
在平衡二叉排序树里,算法的时间复杂度为O(log2(n)),明显,这里的算法时间复杂度是取决于树的深度的,想一想,一个节点只能存储有限的数据,一个结点最多只能有两颗子树,这样一来,数据一多,树的深度就很大,因此,算法的时间复杂度很容易就变得很大,这种问题有什么解决办法呢?肯定是减少树的深度啊!,怎么减少树的深度呢?可以多增加几个子树啊!子树之间也是有序的,这样一来,树的深度不久降下来了吗,这样的话,这种多子树的平衡术的时间复杂度就为logm(n),其中的m为子树的个数,m越大,算法时间复杂度就很小了!
按照这样的思路,我们新提出来一种树,那就是B树了,B树通常被描述为m阶B树,m阶B树的定义如下:
1.每个结点最多只能有m颗子树()
2.根节点至少有2颗子树(根节点子树数目>=2&&<=m)
3.除了根节点之外的非叶结点至少有|_m/2_|颗子树(>=|_m/2_|&&<=m)
4.所有的叶子结点都在同一层()
好了,有了以上的定义,下面可以给出B树的数据结构了
#include<iostream> #define M 100 typedef char KeyType; //m阶B树表示:这个树每个节点最多能有m颗子树,根节点最少有2颗子树,非根的非叶子结点最少有ceil(m/2)颗子树 typedef struct _B_Node { struct _B_Node* childTree[M+1];//M+1个子树 int keyNum;//关键字个数,keyNum+1为子树个数 struct _B_Node* parent; KeyType key[M+1];//m个关键字,第0个不用 }B_Node,*BTreeRoot;
接下来是基于B树的查找
//返回查找成功或者失败,成功时:node为该关键字所在结点的地址,number为该关键字在他节点中的位置, //失败时:返回false,node为应该插入的结点,number为这个节点中应该插入的位置, bool find_By_Btree(BTreeRoot root,int* number,B_Node* &node,KeyType k) { B_Node *p=root; int i=1; while (p) { for (i = 1; i <=p->keyNum; i++) { if (p->key[i]==k) { *number=i; node=p; return true; } else if (p->key[i]<k) { continue; } else { break; } } node=p; p=p->childTree[i-1]; } if (p==nullptr) { *number=i; node=p->parent; return false; } }
算法分析:通过对B树的树形的分析,不难发现,B树的时间复杂度为O(logm(n)),也可以写为log(n)