B树也是用来存放一组具有关键码的词条的,它的特点也非常的鲜明,首先每一个节点未必只有两个分叉,可以拥有更多的分叉。其次,所有底层节点的深度都是完全一致的,从这个意义上讲它是一种理想平衡的搜索树。最后,也是最重要的一个整体特征:相对于常规的二叉查找树,B树会显得更宽、更矮,而且也是可以动态变化的。B树的设计者将其定义为一种平衡的多路(multi-way)搜索树,与之前的二路搜索树在本质上是等价的,因为每一个内部(internal)节点都可以认为是由若干个二路节点经过适当的合并以后得到的
举个例子,看这个
不看方框,这就是一颗BST,看了方框,把父子两代合并为一个节点,这棵树就变成了这样:
2代合并后,每个节点都将拥有3个关键码,以及4个分支。推而广之,3代合并后,每个节点里含有7个关键码以及8路分支。一般而言, 如果每d代都进行一次合并,那么之后的每个节点都将拥有2的d次方路分支,以及相应再减少1个单位的关键码。那既然这种多路的搜索树与二路搜索树并没有本质的区别,那还发明个鬼啊,难道这是灌水论文?
非也非也,问题在于我们通常都是按多个层次来分级组织的存储系统,如果使用B树可以针对不同层次间的通信,大大降低IO访问的次数,从而极大的提高计算效率。那难道之前很熟悉的AVL树在这方面还不够么?
我们来做个小学算术,有一个由109,1G个记录的数据集。如果将它们组织为一棵AVL树,高度大致为30层。也就是说在最坏的情况下,单次查找需要深入30层,而每一层我们都需要执行一次IO操作,而每一次只能读一个值,这就很得不偿失了。那B树呢,B树中合并后节点同时包含多个而不是单个关键码,因此在B树中每下降一层,都能以内部节点为单位读入一组而不是单个关键码,从而将外存批量访问的特点转化为实在的优点。一个内部节点的规模取决于数据缓冲页面的大小,通常的情况下都是几个KB。比如若将内部节点的规模取做256,28。那同样存1G个记录的B树高度不会超过4,这就意味着即便在最坏的情况下,单次查找所需的IO也同样不超过4次,这是一个很大的提高了。或许有些人会有疑问:这不都是常数级别么?就渐近意义而言是这样,但是当这个常数的每一个单位都相当于105至106时,就必须计较一下了,因为我们的内存和时间都是有限的。就像1秒和1天都可以视作是常数,但是对于有限的人生来说,却有本质的区别,4年读一个学士大家能接受,如果换成30年,就没人这么干了。