查找 - 树上的查找 - B-树

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了查找 - 树上的查找 - B-树相关的知识,希望对你有一定的参考价值。

参考技术A

  当查找的文件较大 且存放在磁盘等直接存取设备中时 为了减少查找过程中对磁盘的读写次数 提高查找效率 基于直接存取设备的读写操作以 页 为单位的特征

   年R Bayer和E M McCreight提出了一种称之为B 树的多路平衡查找树 它适合在磁盘等直接存取设备上组织动态的查找表

  B 树的定义

   B 树的定义

  一棵m(m≥ )阶的B 树是满足如下性质的m叉树

  ( )每个结点至少包含下列数据域

  (j P K l P K … K i P i )

  其中

  j为关键字总数

  K i ( ≤i≤j)是关键字 关键字序列递增有序 K <k 。.lishixinzhi<="" i="" <…

  P i (0≤i≤j)是孩子指针。对于叶结点,每个P i 为空指针。

  注意:

  ①实用中为节省空间,叶结点中可省去指针域P i ,但必须在每个结点中增加一个标志域leaf,其值为真时表示叶结点,否则为

  内部结点。

  ②在每个内部结点中,假设用keys(Pi)来表示子树Pi中的所有关键字,则有:

  keys(P 0 ) <k )<="" <keys(p="" )<k="" 1="" i="" <…

  即关键字是分界点,任一关键字Ki左边子树中的所有关键字均小于K i ,右边子树中的所有关键字均大于K i 。

  (2)所有叶子是在同一层上,叶子的层数为树的高度h。

  (3)每个非根结点中所包含的关键字个数j满足:

  

  (4)若树非空,则根至少有1个关键字,故若根不是叶子,则它至少有2棵子树。根至多有m-1个关键字,故至多有m棵子树。

  2、B-树的结点规模

  在大多数系统中,B-树上的算法执行时间主要由读、写磁盘的次数来决定,每次读写尽可能多的信息可提高算法得执行速度。

  B-树中的结点的规模一般是一个磁盘页,而结点中所包含的关键字及其孩子的数目取决于磁盘页的大小。

  注意:

  ①对于磁盘上一棵较大的B-树,通常每个结点拥有的孩子数目(即结点的度数)m为50至2000不等

  ②一棵度为m的B-树称为m阶B-树。

  ③选取较大的结点度数可降低树的高度,以及减少查找任意关键字所需的磁盘访问次数。

  【例】下图给出了一棵高度为3的1001阶B-树。

  

  说明:

  ①每个结点包含1000个关键字,故在第三层上有100多万个叶结点,这些叶节点可容纳10亿多个关键字。

  ②图中各结点内的数字表示关键字的数目。

  ③通常根结点可始终置于主存中,因此在这棵B-树中查找任一关键字至多只需二次访问外存。

  3、B-树的存储结构

  #define Max l000 //结点中关键字的最大数目:Max=m-1,m是B-树的阶

  #define Min 500 //非根结点中关键字的最小数目:Min=┌m/2┐-1

  typedef int KeyType; //KeyType应由用户定义

  typedef struct node //结点定义中省略了指向关键字代表的记录的指针

  int keynum; //结点中当前拥有的关键字的个数,keynum《Max

  KeyType key[Max+1]; //关键字向量为key[1..keynum],key[0]不用。

  struct node *parent; //指向双亲结点

  struct node *son[Max+1];//孩子指针向量为son[0..keynum]

  BTreeNode;

  typedef BTreeNode *BTree;

  注意:

  为简单起见,以上说明省略了辅助信息域。在实用中,与每个关键字存储在一起的不是相关的辅助信息域,而是一个指向另一磁

  盘页的指针。磁盘页中包含有该关键字所代表的记录,而相关的辅助信息正是存储在此记录中。

  有的B-树(如第10章介绍的B+树)是将所有辅助信息都存于叶结点中,而内部结点(不妨将根亦看作是内部结点)中只存放关键字和

  指向孩子结点的指针,无须存储指向辅助信息的指针,这样使内部结点的度数尽可能最大化。

  4、5阶B-树示例

  【例】下图给出了一棵包含24个英文字母的5阶B-树的存储结构图。

  

  说明:

  按照定义,在5阶B-树里,根中的关键字数目可以是1~4,子树数可以是2~5;其它的结点中关键字数目可以是2~4,若该结点

  不是叶子,则它可以有3~5棵子树。

  B-树上的基本运算

  1、B-树的查找

  (1)B-树的查找方法

  在B-树中查找给定关键字的方法类似于二叉排序树上的查找。不同的是在每个结点上确定向下查找的路径不一定是二路而是

  keynum+1路的。

  对结点内的存放有序关键字序列的向量key[l..keynum] 用顺序查找或折半查找方法查找。若在某结点内找到待查的关键字K,则

  返回该结点的地址及K在key[1..keynum]中的位置;否则,确定K在某个key[i]和key[i+1]之间结点后,从磁盘中读son[i]所指的

  结点继续查找……。直到在某结点中查找成功;或直至找到叶结点且叶结点中的查找仍不成功时,查找过程失败。

  【例】下图中左边的虚线表示查找关键字1的过程,它失败于叶结点的H和K之间空指针上;右边的虚线表示查找关键字S的过程,并成

  功地返回S所在结点的地址和S在key[1..keynum]中的位置2。

  

  (2)B-树的查找算法

  BTreeNode *SearchBTree(BTree T,KeyType K,int *pos)

   //在B-树T中查找关键字K,成功时返回找到的结点的地址及K在其中的位置*pos

  //失败则返回NULL,且*pos无定义

  int i;

  T→key[0]=k; //设哨兵.下面用顺序查找key[1..keynum]

  for(i=T->keynum;K key[i];i--); //从后向前找第1个小于等于K的关键字

  if(i>0 && T->key[i]==1) //查找成功,返回T及i

  *pos=i;

  return T;

   //结点内查找失败,但T->key[i] <k key[i+1],下一个查找的结点应为 </k

  //son[i]

  if(!T->son[i]) //*T为叶子,在叶子中仍未找到K,则整个查找过程失败

  return NULL;

  //查找插入关键字的位置,则应令*pos=i,并返回T,见后面的插入操作

  DiskRead(T->son[i]); //在磁盘上读人下一查找的树结点到内存中

  return SearchBTree(T->Son[i],k,pos); //递归地继续查找于树T->son[i]

  (3)查找操作的时间开销

  B-树上的查找有两个基本步骤:

  ①在B-树中查找结点,该查找涉及读盘DiskRead操作,属外查找;

  ②在结点内查找,该查找属内查找。

  查找操作的时间为:

  ①外查找的读盘次数不超过树高h,故其时间是O(h);

  ②内查找中,每个结点内的关键字数目keynum <m(m是b-树的阶数),故其时间为o(nh)。 p=""> </m(m是b-树的阶数),故其时间为o(nh)。>

  注意:

  ①实际上外查找时间可能远远大于内查找时间。

  ②B-树作为数据库文件时,打开文件之后就必须将根结点读人内存,而直至文件关闭之前,此根一直驻留在内存中,故查找时

  可以不计读入根结点的时间。

  2、B-树的插入和生成

  B-树的生成是从空树起,逐个插入关键字而得到的。

  (1)插入关键字K的方法

  首先在树中查找K,若找到则直接返回(假设不处理相同关键字的插入);否则查找操作必失败于某个叶子上,然后将K插入该叶子

  中。若该叶子结点原来是非满(指keynum <max,即结点中原有的关键字总数小于m-1)的,则插入k后并未破坏b-树的性质,故插入k后 p=""> </max,即结点中原有的关键字总数小于m-1)的,则插入k后并未破坏b-树的性质,故插入k后>

  即完成了插入操作;若该结点原为满,则K插入后keynum=m,违反B-树性质(3),故须调整使其维持B-树性质不变。

  调整操作:

  

  注意:

  当

和新结点的地址一起插入已满的双亲后,双亲也要做分裂操作。最坏情况是,从 *** 入的叶子到根的路径上各结点

  均是满结点,此时,插入过程中的分裂操作一直向上传播到根。当根分裂时,因根没有双亲,故需建立一个新的根,此时树长高一层

  。

  (2)B-树的生成

  由空树开始,逐个插入关键字,即可生成B-树。

  【例】以关键字序列(a,g,f,b,k,d,h,m,i,e, s,i,r,x,c,l,n,t,u,p)建立一棵5阶B-树的生长过程

  注意:

  ①当一结点分裂时所产生的两个结点大约是半满的,这就为后续的插入腾出了较多的空间,尤其是当m较大时,往这些半满的空间

  中插入新的关键字不会很快引起新的分裂。

  ②向上插人的关键字总是分裂结点的中间位置上的关键字,它未必是正待插入该分裂结点的关键字。因此,无论按何次序插入关

  键字序列,树都是平衡的。

  3、B-树的删除

  (1)删除操作的两个步骤

B+树

为了提高查找效率,采用了树这种逻辑结构。

科学家先后发明了二叉查找树、二叉排序树、平衡二叉树(AVLTree)、平衡多路查找树(B-树)、B+树

B+树由这些数据结构演化而来,是目前最高效的查找数据结构。

下面说一下这些树:

二叉查找树

二叉查找树中序遍历有序!中序遍历是左->中->右。

但是二叉查找树可以任意构造,因为只要满足中序序列有序,它就是二叉查找树,但是奇形怪状的二叉查找树查找效率不行,所以加了一些约束:平衡二叉树诞生了!

平衡二叉树

平衡二叉树也是二叉查找树,但是有个条件:平衡二叉树必须是任何一个节点的左右子树最大高度差为1,这才是平衡的。

向AVL树中插入或删除一个节点,这可能会导致AVL失去平衡,AVL失去平衡有四种姿态:

LL:根节点的左孩子的左孩子还有非空节点,

RR:根节点的右孩子的右孩子还有非空节点,

LR:根节点的左孩子的右孩子还有非空节点,

RL:根节点的右孩子的左孩子还有非空节点,

如果增删节点失去平衡,需要旋转使AVL恢复平衡,四种不平衡姿态对应四种不同旋转方式:

LL的旋转:

RR的旋转:

LR的旋转:

RL的旋转:

平衡多路查找树(B-树)

为磁盘等外存设备设计的一种平衡查找树。

先了解一下磁盘相关知识:

系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的,位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。

InnoDB是MySQL中的一种存储引擎,存储引擎是数据库最核心的组件。

InnoDB存储引擎中有页(Page)的概念,页是其磁盘管理的最小单位。InnoDB存储引擎中默认每个页的大小为16KB,可通过参数innodb_page_size将页的大小设置为4K、8K、16K,MySQL查看页的大小:show variables like ‘innodb_page_size‘

一个磁盘块的存储空间 < 页的大小,因此InnoDB每次申请磁盘空间时都会是若干地址连续磁盘块来达到页的大小16KB。

InnoDB在把磁盘数据读入到磁盘时会以页为基本单位,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘I/O次数,提高查询效率。

B-Tree结构的数据可以让系统高效的找到数据所在的磁盘块,

为了描述B-Tree,首先定义一条记录为一个二元组[key, data] ,key为记录的键值,对应表中的主键值,data为一行记录中除主键外的数据。对于不同的记录,key值互不相同。

一棵m阶B-树的特性:

1.每个节点最多有m个孩子,B树是多叉树

2.除了根节点和叶子节点外,其它每个节点至少有Ceil(m/2)个孩子 m/2往大取整

3.若根节点不是叶子节点,则至少有2个孩子

4.所有叶子节点都在同一层,且不包含其它关键字信息

5.先写到这,先缓缓...,下次接着写^-^

参考:

https://blog.csdn.net/ifollowrivers/article/details/73614549

以上是关于查找 - 树上的查找 - B-树的主要内容,如果未能解决你的问题,请参考以下文章

联合索引在B+树上的存储结构及数据查找方式

算法实现在二叉排序树上查找关键值key

树897. 递增顺序查找树

二叉查找树 Binary Serach Tree

数据结构 简单算法实现在二叉排序树上查找关键值k

(14)联合索引存储结构&查找方式