码迷,mamicode.com
首页 > Web开发 > 详细

<html>

时间:2017-08-11 23:06:29      阅读:340      评论:0      收藏:0      [点我收藏+]

标签:weixin   磁头   black   rom   ane   收藏   tar   ued   磁盘存储   

  B~树               

1.前言:

动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree),红黑树 (Red-Black Tree ),B-tree/B+-tree/ B*-tree (B~Tree)。前三者是典型的二叉查找树结构。其查找的时间复杂度O(log2N)与树的深度相关,那么降低树的深度自然对查找效率是有所提高的;另一个实际问题:就是大规模数据存储中。实现索引查询这样一个实际背景下。树节点存储的元素数量是有限的(假设元素数量非常多的话,查找就退化成节点内部的线性查找了),这样导致二叉查找树结构因为树的深度过大而造成磁盘I/O读写过于频繁。进而导致查询效率低下(为什么会出现这样的情况。待会在外部存储器-磁盘中有所解释),那么怎样降低树的深度(当然是不能降低查询的数据量),一个主要的想法就是:採用多叉树结构(因为树节点元素数量是有限的,自然该节点的子树数量也就是有限的)。

这样我们就提出了一个新的查找树结构——多路查找树。

依据平衡二叉树的启示,自然就想到平衡多路查找树结构。也就是这篇文章所要阐述的主题B~tree(B树结构)。B-tree这棵奇妙的树是在Rudolf BayerEdward M. McCreight(1970)写的一篇论文《Organization and Maintenance of Large Ordered Indices》中首次提出。

详细介绍能够參考wikipedia中的介绍:http://en.wikipedia.org/wiki/B-tree,当中还阐述了B-tree名字来源以及相关的开源地址。

在開始介绍B~tree之前,先了解下相关的硬件知识,才干非常好的了解为什么须要B~tree这样的外存数据结构。

2.外存储器磁盘

计算机存储设备一般分为两种内存储器(main memory)和外存储器(external memory)内存存取速度快。但容量小,价格昂贵。并且不能长期保存数据(在不通电情况下数据会消失)

外存储器—磁盘是一种直接存取的存储设备(DASD)。它是以存取时间变化不大为特征的。

能够直接存取不论什么字符组,且容量大、速度较其他外存设备更快。

2.1磁盘的构造

磁盘时一个扁平的圆盘(与电唱机的唱片相似)。盘面上有很多称为磁道的圆圈。数据就记录在这些磁道上。磁盘能够是单片的,也能够是由若干盘片组成的盘组。每一盘片上有两个面。例如以下图6片盘组为例,除去最顶端和最底端的外側面不存储数据之外,一共同拥有10个面能够用来保存信息。

                            技术分享

 

当磁盘驱动器运行读/写功能时。

盘片装在一个主轴上。并绕主轴快速旋转,当磁道在读/写头(又叫磁头下通过时。就能够进行数据的读 / 写了。

一般磁盘分为固定头盘(磁头固定)和活动头盘。

固定头盘的每一个磁道上都有独立的磁头,它是固定不动的。专门负责这一磁道上数据的读/写。

活动头盘 (如上图)的磁头是可移动的。每一个盘面上仅仅有一个磁头(磁头是双向的。因此正反盘面都能读写)。它能够从该面的一个磁道移动到另一个磁道。全部磁头都装在同一个动臂上,因此不同盘面上的全部磁头都是同一时候移动的(行动整齐划一)

当盘片绕主轴旋转的时候,磁头与旋转的盘片形成一个圆柱体。

各个盘面上半径同样的磁道组成了一个圆柱面。我们称为柱面

因此,柱面的个数也就是盘面上的磁道数。

2.2磁盘的读/写原理和效率

磁盘上数据必须用一个三维地址唯一标示:柱面号、盘面号、块号(磁道上的盘块)

/写磁盘上某一指定数据须要以下3个步骤:

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

(2)  如上图6盘组示意图中,全部磁头都定位到了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

所以。在大规模数据存储方面。大量数据存储在外存磁盘中,而在外存磁盘中读取/写入块(block)中某数据时,首先须要定位到磁盘中的某块。怎样有效地查找磁盘中的数据。须要一种合理高效的外存数据结构,就是以下所要重点阐述的B-tree结构,以及相关的变种结构:B+-tree结构和B*-tree结构。

3.B-tree

 

B-tree又叫平衡多路查找树。一棵m阶的B-tree (m叉树)的特性例如以下:

(当中ceil(x)是一个取上限的函数)

1)  树中每一个结点至多有m个孩子;

2)  除根结点和叶子结点外。其他每一个结点至少有有ceil(m / 2)个孩子;

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

4)  全部叶子结点都出如今同一层,叶子结点不包括不论什么keyword信息(能够看做是外部结点或查询失败的结点,实际上这些结点不存在,指向这些结点的指针都为null)

5)  每一个非终端结点中包括有n个keyword信息: (nP0K1P1K2P2......KnPn)

当中:

             a)   Ki (i=1...n)为keyword。且keyword按顺序排序K(i-1)< Ki

             b)   Pi为指向子树根的接点,且指针P(i-1)指向子树种全部结点的keyword均小于Ki。但都大于K(i-1)

      c)   keyword的个数n必须满足: ceil(m / 2)-1 <= n <= m-1

B-tree中的每一个结点依据实际情况能够包括大量的keyword信息和分支(当然是不能超过磁盘块的大小,依据磁盘驱动(disk drives)的不同,一般块的大小在1k~4k左右)。这样树的深度降低了。这就意味着查找一个元素仅仅要非常少结点从外存磁盘中读入内存。非常快訪问到要查找的数据。

 

 

技术分享

为了简单,这里用少量数据构造一棵3叉树的形式

上面的图中比方根结点,当中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;

假如每一个盘块能够正好存放一个B-tree的结点(正好存放2个文件名称)。那么一个BTNode结点就代表一个盘块,而子树指针就是存放另外一个盘块的地址。

模拟查找文件29的过程:

 (1) 依据根结点指针找到文件文件夹的根磁盘块1,将当中的信息导入内存。【磁盘IO操作1次】

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

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

 (4) 此时内存中有两个文件名称2630和三个存储其他磁盘页面地址的数据。

依据算法我们发现26<29<30,因此我们找到指针p2

 (5) 依据p2指针,我们定位到磁盘块8,并将当中的信息导入内存。

【磁盘IO操作3次】

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

分析上面的过程,发现须要3次磁盘IO操作和3次内存查找操作。

关于内存中的文件名称查找,因为是一个有序表结构,能够利用折半查找提高效率。至于3次磁盘IO操作时影响整个B-tree查找效率的决定因素。

当然。假设我们使用平衡二叉树的磁盘存储结构来进行查找,磁盘IO操作最少4次,最多5次。

并且文件越多。B-tree比平衡二叉树所用的磁盘IO操作次数将越少,效率也越高。

上面仅仅介绍了对于B-tree这样的结构的查找过程,还有树节点的插入与删除过程。以及相关的算法和代码的实现,将在以后的深入学习中给出对应的实例

上面简介了利用B-tree这样的结构怎样訪问外存磁盘中的数据的情况,以下咱们通过另外一个实例来对这棵B-tree的插入(insert),删除(delete)基本操作进行详细的介绍:

以下以一棵5阶B-tree实例进行解说(例如以下图所看到的):

其满足上述条件:除根结点和叶子结点外。其他每一个结点至少有ceil(5/2)=3个孩子(至少2个keyword)。当然最多5个孩子(最多4个keyword)。下图中keyword为大写字母。顺序为字母升序。

结点定义例如以下:

typedef struct{

   int Count;         // 当前节点中关键元素数目

   ItemType Key[4];   // 存储keyword元素的数组

   long Branch[5];    // 伪指针数组。(记录数目)方便推断合并和分裂的情况

} NodeType;

技术分享

插入(insert)操作插入一个元素时。首先在B-tree中是否存在,假设不存在,即在叶子结点处结束,然后在叶子结点中插入该新的元素,注意:假设叶子结点空间足够,这里须要向右移动该叶子结点中大于新插入keyword的元素。假设空间满了以致没有足够的空间去加入新的元素,则将该结点进行“分裂”。将一半数量的keyword元素分裂到新的其相邻右结点中,中间keyword元素上移到父结点中(当然。假设父结点空间满了。也同样须要“分裂”操作),并且当结点中关键元素向右移动了,相关的指针也须要向右移。假设在根结点插入新元素,空间满了,则进行分裂操作,这样原来的根结点中的中间keyword元素向上移动到新的根结点中,因此导致树的高度添加一层。

咱们通过一个实例来逐步解说下。插入以下字符字母到空的5阶B-tree中:C N G A H E K Q M F W L T Z D P R X Y S5序意味着一个结点最多有5个孩子和4个keyword,除根结点外其他结点至少有2个keyword,首先。结点空间足够。4个字母插入同样的结点中,例如以下图:

 

技术分享

当咱们试着插入H时,结点发现空间不够。以致将其分裂成2个结点,移动中间元素G上移到新的根结点中,在实现过程中。咱们把AC留在当前结点中,而HN放置新的其右邻居结点中。例如以下图:

 

技术分享

当咱们插入E,K,Q时,不须要不论什么分裂操作

 

技术分享

插入M须要一次分裂。注意M恰好是中间keyword元素。以致向上移到父节点中

 

技术分享

插入F,W,L,T不须要不论什么分裂操作

 

技术分享

插入Z时,最右的叶子结点空间满了,须要进行分裂操作,中间元素T上移到父节点中,注意通过上移中间元素。树终于还是保持平衡,分裂结果的结点存在2个keyword元素。

 

技术分享

插入D时,导致最左边的叶子结点被分裂,D恰好也是中间元素。上移到父节点中,然后字母P,R,X,Y陆续插入不须要不论什么分裂操作。

 

技术分享

最后,当插入S时,含有N,P,Q,R的结点须要分裂,把中间元素Q上移到父节点中,可是情况来了,父节点中空间已经满了。所以也要进行分裂,将父节点中的中间元素M上移到新形成的根结点中,注意曾经在父节点中的第三个指针在改动后包括DG节点中。

这样详细插入操作的完毕,以下介绍删除操作,删除操作相对于插入操作要考虑的情况多点。

 

技术分享

删除(delete)操作:首先查找B-tree中需删除的元素,假设该元素在B-tree中存在。则将该元素在其结点中进行删除。假设删除该元素后,首先推断该元素是否有左右孩子结点,假设有,则上移孩子结点中的某相近元素到父节点中,然后是移动之后的情况;假设没有,直接删除后。移动之后的情况.。

删除元素,移动对应元素之后,假设某结点中元素数目小于ceil(m/2)-1,则须要看其某相邻兄弟结点是否丰满(结点中元素个数大于ceil(m/2)-1),假设丰满。则向父节点借一个元素来满足条件;假设其相邻兄弟都刚脱贫,即借了之后其结点数目小于ceil(m/2)-1,则该结点与其相邻的某一兄弟结点进行合并成一个结点。以此来满足条件。那咱们通过以下实例来详细了解吧。

以上述插入操作构造的一棵5阶B-tree为例。依次删除H,T,R,E

首先删除元素H,当然首先查找HH在一个叶子结点中,且该叶子结点元素数目3大于最小元素数目ceil(m/2)-1=2。则操作非常easy。咱们仅仅须要移动K至原来H的位置,移动LK的位置(也就是结点中删除元素后面的元素向前移动)

 

技术分享

下一步。删除T,因为T没有在叶子结点中。而是在中间结点中找到,咱们发现他的继承者W(字母升序的下个元素),将W上移到T的位置,然后将原包括W的孩子结点中的W进行删除,这里恰好删除W后,该孩子结点中元素个数大于2,无需进行合并操作。

 

技术分享

下一步删除RR在叶子结点中,可是该结点中元素数目为2,删除导致仅仅有1个元素,已经小于最小元素数目ceil(5/2)-1=2,假设其某个相邻兄弟结点中比較丰满(元素个数大于ceil(5/2)-1=2),则能够向父结点借一个元素,然后将最丰满的相邻兄弟结点中上移最后或最前一个元素到父节点中,在这个实例中。右相邻兄弟结点中比較丰满(3个元素大于2),所以先向父节点借一个元素W下移到该叶子结点中。取代原来S的位置,S前移。然后X在相邻右兄弟结点中上移到父结点中。最后在相邻右兄弟结点中删除X。后面元素前移。

 

 

技术分享

最后一步删除E删除后会导致非常多问题,因为E所在的结点数目刚好达标。刚好满足最小元素个数(ceil(5/2)-1=2,而相邻的兄弟结点也是同样的情况,删除一个元素都不能满足条件,所以须要该节点与某相邻兄弟结点进行合并操作;首先移动父结点中的元素(该元素在两个须要合并的两个结点元素之间)下移到其子结点中。然后将这两个结点进行合并成一个结点。

所以在该实例中,咱们首先将父节点中的元素D下移到已经删除E而仅仅有F的结点中,然后将含有DF的结点和含有A,C的相邻兄弟结点进行合并成一个结点。

 

技术分享

或许你觉得这样删除操作已经结束了。事实上不然,在看看上图。对于这样的特殊情况,你马上会发现父节点仅仅包括一个元素G,没达标,这是不能够接受的。

假设这个问题结点的相邻兄弟比較丰满,则能够向父结点借一个元素。

假设这时右兄弟结点(含有Q,X)有一个以上的元素(Q右边还有元素),然后咱们将M下移到元素非常少的子结点中。将Q上移到M的位置。这时,Q的左子树将变成M的右子树。也就是含有NP结点被依附在M的右指针上。所以在这个实例中,咱们没有办法去借一个元素,仅仅能与兄弟结点进行合并成一个结点,而根结点中的唯一元素M下移到子结点,这样,树的高度降低一层。

 

技术分享

为了进一步详细讨论删除的情况。

再举另外一个实例:

这里是一棵不同的5阶B-tree。那咱们试着删除C

 

技术分享

于是将删除元素C的右子结点中的D元素上移到C的位置,可是出现上移元素后。仅仅有一个元素的结点的情况。

 

技术分享

又因为含有E的结点,其相邻兄弟结点才刚脱贫(最少元素个数为2),不可能向父节点借元素。所以仅仅能进行合并操作,于是这里将含有A,B的左兄弟结点和含有E的结点进行合并成一个结点。

 

技术分享

这样又出现仅仅含有一个元素F结点的情况,这时,其相邻的兄弟结点是丰满的(元素个数为3>最小元素个数2),这样就能够想父结点借元素了,把父结点中的J下移到该结点中,对应的假设结点中J后有元素则前移,然后相邻兄弟结点中的第一个元素(或者最后一个元素)上移到父节点中,后面的元素(或者前面的元素)前移(或者后移);注意含有KL的结点曾经依附在M的左边,如今变为依附在J的右边。

这样每一个结点都满足B-tree结构性质。

 

技术分享

假设想了解相关代码,见最后參考。

 

4.B+-tree

B+-tree:是应文件系统所需而产生的一种B-tree的变形树。

一棵m阶的B+-treem阶的B-tree的差异在于:

       1.n棵子树的结点中含有n个keyword。 (B-treen棵子树有n-1个keyword)

       2.全部的叶子结点中包括了全部keyword的信息,及指向含有这些keyword记录的指针,且叶子结点本身依keyword的大小自小而大的顺序链接。 (B-tree的叶子节点并没有包括全部须要查找的信息)

       3.全部的非终端结点能够看成是索引部分,结点中仅含有其子树根结点中最大(或最小)keyword。 (B-tree的非终节点也包括须要查找的有效信息)

 

 

技术分享

a)      为什么说B+B-tree更适合实际应用中操作系统的文件索引和数据库索引?

1) B+-tree的磁盘读写代价更低

B+-tree的内部结点并没有指向keyword详细信息的指针。因此其内部结点相对B-tree更小。

假设把全部同一内部结点的keyword存放在同一盘块中,那么盘块所能容纳的keyword数量也越多。一次性读入内存中的须要查找的keyword也就越多。

相对来说IO读写次数也就降低了。

     举个样例,假设磁盘中的一个盘块容纳16bytes,而一个keyword2bytes,一个keyword详细信息指针2bytes。一棵9B-tree(一个结点最多8个keyword)的内部结点须要2个盘快。

B+-tree内部结点仅仅须要1个盘快。

当须要把内部结点读入内存中的时候,B-tree就比B+-tree多一次盘块查找时间(在磁盘中就是盘片旋转的时间)

2) B+-tree的查询效率更加稳定

因为非终结点并非终于指向文件内容的结点,而仅仅是叶子结点中keyword的索引。所以不论什么keyword的查找必须走一条从根结点到叶子结点的路。全部keyword查询的路径长度同样。导致每一个数据的查询效率相当。

b)      B+-tree的应用: VSAM(虚拟存储存取法)文件(来源论文the ubiquitous Btree 作者:D COMER - 1979 )

 

技术分享 

关于B+-tree的详细介绍将在以后的学习中给出实例。待写。。。

5.B*-tree

B*-treeB+-tree的变体,在B+-tree的非根和非叶子结点再添加指向兄弟的指针;B*-tree定义了非叶子结点keyword个数至少为(2/3)*M。即块的最低使用率为2/3(取代B+树的1/2)。给出了一个简单实例,例如以下图所看到的:

 

技术分享

B+-tree的分裂:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据拷贝到新结点。最后在父结点中添加新结点的指针。B+-tree的分裂仅仅影响原结点和父结点,而不会影响兄弟结点。所以它不须要指向兄弟的指针。

B*-tree的分裂:当一个结点满时。假设它的下一个兄弟结点未满。那么将一部分数据移到兄弟结点中,再在原结点插入keyword,最后改动父结点中兄弟结点的keyword(因为兄弟结点的keyword范围改变了);假设兄弟也满了,则在原结点与兄弟结点之间添加新结点,并各复制1/3的数据到新结点,最后在父结点添加新结点的指针。

所以,B*-tree分配新结点的概率比B+-tree要低,空间使用率更高。

 

6.总结

      B-treeB+-treeB*-tree总结例如以下: 

       B-tree:有序数组+平衡多叉树。

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

       B*-tree:一棵丰满的B+-tree

 

        在大规模数据存储的文件系统中,B~tree系列数据结构,起着非常关键的数据。对于存储不同的数据。节点相关的信息也是有所不同,这里依据自己的理解,画的一个查找以职工号为keyword,职工号为38的记录的简单示意图。

(这里假设每一个物理块容纳3个索引,磁盘的I/O操作的基本单位是块(block),磁盘訪问非常费时,採用B+-tree有效的降低了訪问磁盘的次数。)

对于像MySQLDB2Oracle等数据库中的索引结构有待深入的了解才行。只是网上能够找到非常多B-tree相关的开源码能够用来研究。

 

技术分享

參考文献(google下能够找到相关论文下载)以及相关网址:

1.     Organization and Maintenance of Large Ordered Indices

2.     the ubiquitous B tree

3.     http://en.wikipedia.org/wiki/Btree (给出了国外一些开源地址)

4.     http://cis.stvincent.edu/html/tutorials/swd/btree/btree.html(include C++ source code)

5.     http://slady.net/java/bt/view.php(假设了解了B-tree结构,该地址能够在线对该结构进行查找(search),插入(insert)。删除(delete)操作。

版权声明:本文为Sunface原创文章。请任意转载并注明出处。同一时候欢迎大家增加Golang隐修会,QQ群894864,大神非常多。

举报

  • 本文已收录于下面专栏:

相关文章推荐

数据库检索 索引之--- B 树

B树索引是一个典型的树结构,始终是平衡的。也就是说 从Root节点到 Leaf 节点的不论什么一个路径都是等距离的。其包括的组件主要是: ? ? ? ? ? ? 叶子节点(Leaf node):包括...

数据结构读书笔记

平衡二叉树代码编写 http://www.cppblog.com/cxiaojia/archive/2012/08/20/187776.html

从B 树、B+ 树、B* 树谈到R 树 ---从磁盘读取考虑

第一节、B树、B+树、B*树 1.前言: 动态查找树主要有:二叉查找树(Binary Search Tree),平衡二叉查找树(Balanced Binary Search Tree)。红黑树(Red...

B+,B*到R树

从B树、B+树、B*树谈到R 树 文件夹(?)[+]第一节B树B树B树4B树的高度第二节R树处理空间存储问题简单介绍R树的数据结构叶子结点的结构非叶子结点...

B , B+ ,B*树

从B 树、B+ 树、B* 树谈到R 树? 作者:July、weedge、Frankie。编程艺术室出品。 说明:本文从B树開始谈起。然后论述B+树、B*树。最后谈到R 树。当中B树、B+树及B*树...

从B-tree说起

从B 树、B+ 树、B* 树谈到R 树 ? 作者:July、weedge、Frankie。编程艺术室出品。

说明:本文从B树開始谈起。然后论述B+树、B*树,最后谈到R 树。

当中B树...

B-Tree

B~树??????????????? 1.前言: 动态查找树主要有:二叉查找树(Binary Search Tree)。平衡二叉查找树(Balanced Binary Search Tree),红...

从B 树、B+ 树、B* 树谈到R 树

从B 树、B+ 树、B* 树谈到R 树

整个数据库搜索数据

------------------第一种方法---------------------- CREATE PROC sp_ValueSearch @value sql_variant,? --要搜...

利用二分查找法查找数据

要求: 1.随机生成15个不反复的0-100之间的整数组成数组并输出 2.对数组进行排序 3.用户输入某一个数据进行查找,查找到后返回该数据以及该数据的位置 4.若没有查找到则输出没有找到 ...
  • 微博
    微信
    QQ
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多仅仅同意输入30个字)

技术分享

<html>

标签:weixin   磁头   black   rom   ane   收藏   tar   ued   磁盘存储   

原文地址:http://www.cnblogs.com/jhcelue/p/7348194.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
分享档案
周排行
mamicode.com排行更多图片
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!