对B树、B+树、的一些认识

1 、为何需要B树

       在大规模数据存储中,实现索引查询这样一个实际背景下,树节点存储的元素数量是有限的(如果元素数量非常多的话,查找就退化成节点内部的线性查找了),这样导致二叉查找树结构由于树的深度过大而造成磁盘I/O读写过于频繁,进而导致查询效率低下,那么减少树的深度的一个基本的想法就是:采用多叉树结构。磁盘查找存取的次数往往由树的高度所决定,所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,那么便可以有效减少磁盘查找存取的次数。

根据平衡二叉树可以联想到平衡多路查找树结构,也就是B树。

磁盘上数据必须用一个三维地址唯一标示:柱面号、盘面号、块号(磁道上的盘块)读/写磁盘上某一指定数据需要3个步骤:

(1)  首先移动臂根据柱面号使磁头移动到所需要的柱面上,这一过程被称为定位或查找 

(2) 所有磁头都定位到了10个盘面的10条磁道上(磁头都是双向的)。这时根据盘面号来确定指定盘面上的磁道。

(3) 盘面确定以后,盘片开始旋转,将指定块号的磁道段移动至磁头下。

当访问某一具体信息,由3部分时间组成:

● 查找时间(seek time) Ts: 完成上述步骤(1)所需要的时间。这部分时间代价最高,最大可达到0.1s左右。

● 等待时间(latency time) Tl: 完成上述步骤(3)所需要的时间。由于盘片绕主轴旋转速度很快,一般为7200/(电脑硬盘的性能指标之一家用的普通硬盘的转速一般有5400rpm(笔记本)7200rpm几种)因此一般旋转一圈大约0.0083s

● 传输时间(transmission time) Tt: 数据通过系统总线传送到内存的时间,一般传输一个字节(byte)大概0.02us=2*10^(-8)s

磁盘读取数据是以盘块(block)为基本单位的。位于同一盘块中的所有数据都能被一次性全部读取出来。而磁盘IO代价主要花费在查找时间Ts上。因此我们应该尽量将相关信息存放在同一盘块,同一磁道中。或者至少放在同一柱面或相邻柱面上,以求在读/写信息时尽量减少磁头来回移动的次数,避免过多的查找时间Ts。所以正好适用所说的B树,减小深度,即可减小搜索的时间。

2、B树

    B 树是为了磁盘或其它存储设备而设计的一种多叉(B树每个内结点有多个分支,即多叉)平衡查找树。。许多数据库系统都一般使用B树或者B树的各种变形结构来存储信息。

树与红黑树最大的不同在于,B树的结点可以有许多子女。和红黑树一样,一棵含n个结点的B树的高度也为O(lgn),但可能比一棵红黑树的高度小许多,应为它的分支因子比较大。所以,B树可以在O(logn)时间内,实现各种如插入(insert),删除(delete)等动态集合操作。

如上图所示,即是一棵B树,一棵关键字为英语中辅音字母的B树,现在要从树种查找字母R(包含n[x]个关键字的内结点x,x有n[x]+1]个子女(也就是说,一个内结点x若含有n[x]个关键字,那么x将含有n[x]+1个子女)。所有的叶结点都处于相同的深度,带阴影的结点为查找字母R时要检查的结点)。

 用阶定义的B树

    B 树又叫平衡多路查找树。一棵m阶的 (注:切勿简单的认为一棵m阶的B树是m叉树,虽然存在四叉树八叉树KD,及vp/R树/R*树/R+树/X树/M树/线段树/希尔伯特R树/优先R树等空间划分树,但与B树完全不等同)的特性如下

  1. 树中每个结点最多含有m个孩子(m>=2);

  2. 除根结点和叶子结点外,其它每个结点至少有[ceil(m / 2)]个孩子(其中ceil(x)是一个取上限的函数);

  3. 若根结点不是叶子结点,则至少有2个孩子(特殊情况:没有孩子的根结点,即根结点为叶子结点,整棵树只有一个根节点);

  4. 所有叶子结点都出现在同一层,叶子结点不包含任何关键字信息(可以看做是外部接点或查询失败的接点,实际上这些结点不存在,指向这些结点的指针都为null);

  5. 每个非终端结点中包含有n个关键字信息: (n,P0,K1,P1,K2,P2,......,Kn,Pn)。其中:
           a)   Ki (i=1...n)为关键字,且关键字
    按顺序升序排序K(i-1)< Ki。 
           b)   Pi为指向子树根的接点,且指针P(i-1)指向子树种所有结点的关键字均小于Ki,但都大于K(i-1)。 
           c)   关键字的个数n必须满足: [ceil(m / 2)-1]<= n <= m-1。
    如下图所示:

  • 也可以这样理解:每个非根的内结点至多有m个子女,每个非根的结点必须至少含有m-1个关键字,如果树是非空的,则根结点至少包含一个关键字;

  • 每个结点可包含至多2m-1个关键字。所以一个内结点至多可有2m个子女。如果一个结点恰好有2m-1个关键字,我们就说这个结点是满的。

  • 当关键字数m=2(t=2的意思是,Mmin=2,m可以>=2)时的B树是最简单的有很多人会因此误认为B树就是二叉查找树,但二叉查找树就是二叉查找树,B树就是B树,B树是一棵含有m(m>=2)个关键字的平衡多路查找树,此时,每个内结点可能因此而含有2个、3个或4个子女,亦即一棵2-3-4树,然而在实际中,通常采用大得多的t值。

3 B 树的类型和节点定义:

#define m 1024

struct BTNode;

typedef struct BTNode* PBTNode;
struct BTNode{
   int keyNum;//实际关键字个数,keyNum<m
   PBTNode parent;//指向父节点
   PBTNode *ptr;//子树指针向量;
   KeyType *key;//关键字向量
}
typedef struct BTNode* BTree;
typedef BTree *PBTree;

 

在这里用少量数据构造一棵3叉树的形式,实际应用中的B树结点中关键字很多的。上面的图中比如根结点,其中17表示一个磁盘文件的文件名;小红方块表示这个17文件内容在硬盘中的存储位置;p1表示指向17左子树的指针。

typedef struct {
    /*文件数*/
    int  file_num;
    /*文件名(key)*/
    char * file_name[max_file_num];
    /*指向子节点的指针*/
     BTNode * BTptr[max_file_num+1];
     /*文件在硬盘中的存储位置*/
     FILE_HARD_ADDR offset[max_file_num];
}BTNode;

查找29时,可以有一下过程:

  1. 根据根结点指针找到文件目录的根磁盘块1,将其中的信息导入内存。【磁盘IO操作 1次】    

  2. 此时内存中有两个文件名17、35和三个存储其他磁盘页面地址的数据。根据算法我们发现:17<29<35,因此我们找到指针p2。

  3. 根据p2指针,我们定位到磁盘块3,并将其中的信息导入内存。【磁盘IO操作 2次】    

  4. 此时内存中有两个文件名26,30和三个存储其他磁盘页面地址的数据。根据算法我们发现:26<29<30,因此我们找到指针p2。

  5. 根据p2指针,我们定位到磁盘块8,并将其中的信息导入内存。【磁盘IO操作 3次】    

  6. 此时内存中有两个文件名28,29。根据算法我们查找到文件名29,并定位了该文件内存的磁盘地址。

发现一共需要3次磁盘IO操作和3次内存查找操作。IO操作是影响整个B树查找效率的决定因素。

B树的高度:

设B树某一个非叶子节点包含N个关键字,则该非叶子节点含有N+1个结点,所有的叶子结点在第Q层;

通过根至少有两个孩子,则第二层至少有两个结点,除根和叶子外,其他结点至少有ceil(m/2)个孩子,则第三层至少2*ceil(m/2)个孩子,第四层至少2*ceil(m/2^2)个孩子,可以类推,在第Q层至少2*ceil(m/2^(Q-2))个结点,有N+1>=2*ceil(m/2^(Q-2)则Q<=log(ceil(m/2))(N+1)/2)+2;

当B树包含N个关键字时,B树的最大高度为l-1(因为计算B树高度时,叶结点所在层不计算在内),即:l - 1 = log┌m/2┐((N+1)/2 )+1

4 、B+树

是应文件系统所需产生的一种B树的变形树。

m阶的B+树和m阶的B树的异同点:

1、有n个子树的结点含有n-1个关键字;

2、所有叶子结点中包含了全部关键字的信息,以及所指向这关键字的指针,且由小到大顺序链接。

3、所有的非终端结点可以看成是索引部分,结点中仅包含有其子树根节点中最大或最小关键字。

B+树更适合实际应用中操作系统的文件索引和数据索引:理由如下

1、磁盘读写代价更低    

    B+树的内部结点没有指向关键字具体信息的指针,所以其内部结点比B树的小。可以一次性放入更多的关键字在一个盘块中,相对来说IO读写次数就降低了。

2、B+树的查询效率更稳定

     B+树的非终结点不是最终指向文件内容的结点,只是叶子结点中关键字的索引,所以查找时走从根节点到叶子结点的路,所有的路径长度相同,每一个数据的查询效率相当。

书上还有其他的说明:{“B+树还有一个最大的好处,方便扫库,B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了,B+树支持range-query非常方便,而B树不支持。这是数据库选用B+树的最主要原因。

比如要查 5-10之间的,B+树一把到5这个标记,再一把到10,然后串起来就行了,B树就非常麻烦。B树的好处,就是成功查询特别有利,因为树的高度总体要比B+树矮。不成功的情况下,B树也比B+树稍稍占一点点便宜。

    B树比如你的例子中查,17的话,一把就得到结果了,有很多基于频率的搜索是选用B树,越频繁query的结点越往根上走,前提是需要对query做统计,而且要对key做一些变化。

    另外B树也好B+树也好,根或者上面几层因为被反复query,所以这几块基本都在内存中,不会出现读磁盘IO,一般已启动的时候,就会主动换入内存。}

mysql 底层存储是用B+树实现的,知道为什么么。内存中B+树是没有优势的,但是一到磁盘,B+树的威力就出来了

5 B*树

在B+树的基础上,增加了非根和非叶子结点的兄弟指针,定义了非叶子结点关键字的个数至少2/3*M,即块的使用率为2/3

,比B+树的1/2高。

B*树的空间使用率高:

B*树增加结点时,当一个结点满时,如果他的下一个兄弟结点未满,那么将一部分数据转移到兄弟结点中,再在原节点插入关键字,然后修改结点中兄弟结点的关键字。如果兄弟结点也满了,则在原节点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父节点增加新结点的指针。

B+ 树增加结点时,当一个结点满了,分配一个新的结点,并各复制1/2的数据到新结点,最后旨在父节点增加新结点的指针。

6、删除和增加元素

围绕一句话 :关键字少于两个就合并,多余4个就分裂。还有一点,除根节点之外的结点的关键字的个数n必须满足:(ceil(m/2)-1)<=n<=m-1.m表示最多含有m个孩子,n表示关键字数。

7、

B树:有序数组+平衡多叉树;

B+树:有序数组链表+平衡多叉树;

B*树:一棵丰满的B+树。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值