最近学习了算法导轮里B树相关的知识,在此写一篇博客作为总结。

1.引言

B树是为磁盘或其他直接存取的辅助存储设备而设计的一种平衡搜索树。B树类似于红黑树,但它与红黑树最大不同之处在于B树的节点可以拥有很多孩子,因此B树的高度会比红黑树小很多,也因此B树在磁盘I/O方面表现要比红黑树好。(对于磁盘操作最耗时的部分在于磁盘读写,而每次读取一个新的树的节点就必须进行一次磁盘读取,因此节点较大、树高度较小的B树会进行较少的磁盘I/O操作)
 

2.B树的定义

一颗B树的定义如下:
  1. 每个节点x均有如下属性:

    • n表示存储在该节点的关键字个数
    • n个关键字本身key1、key2……keyn以非降序存放,即key1 <= key2 <= …… <= keyn
    • 一个leaf布尔值表示该节点是否为叶节点
  2. 每个内部节点包含了n+1个孩子,叶节点没有孩子
  3. 关键字keyi对存储在各子树中的关键字范围加以分割:即比keyi小的元素在其左子树,比keyi大的元素在其右子树
  4. 每个叶节点具有相同的深度
  5. 每个节点包含的关键字个数有上界与下界。我们定义B树的最小度数为t,则除根节点外的每个节点至少有t-1个关键字,每个节点最多有2t-1个关键字(即每个节点最少有t个孩子,最多有2t个孩子)(当一个节点有2t-1个关键字时,我们称它为满的)。
B树的示意图如下:
上图是一个最小度数为2的B树,因此每个节点拥有1个、2个或3个元素,拥有2个、3个或4个孩子,也被称为2-3-4树。
根节点只有一个元素,因此它拥有两个孩子;两个孩子分别拥有3个和2个元素,因此他们分别拥有4个和3个孩子。
看到DEF叶节点位于关键字C与G的中间,表明了关键字对于存储在各子树中的关键字范围进行了分割,其余同理。
 

3.B树的插入

要讲到树,就不得不提树中关键的插入与删除操作,这里我们先总结B树的插入操作。
当我们往B树中插入一个新的关键字时,由于B树节点的关键字是受到限制的,因此当一个节点关键字数目为2t-1时(该节点是满的),我们就必须进行分裂操作。
 

分裂节点

分裂节点的主要操作为把满节点的中间关键字提升至父节点,把原满节点分裂为中间关键字的两个左右节点
其示意图如下:
对于某个非满的节点x,若其孩子节点x.ci为满的(即孩子节点的关键字数目为2t-1)。则把其孩子节点的中间关键字(S)提升为父节点(x节点)的关键字,并把原孩子节点(x.c节点)分成两个t-1个关键字的节点,分别位于中间关键字(S)的左、右。
还有一种比较特殊的情况就是B树根的分裂:
 
分裂是B树长高的唯一途径,因此分裂是非常重要的。
 

插入

讲完分裂操作在讲插入操作就非常简单了。插入的时候我们通过比较不断地根据关键字的值寻找孩子节点,当发现一个满的节点时便分裂,最后找到对应的叶节点时根据关键字的值插入相应位置即可。
下面是一个插入关键字的例子:
B树的初始状态如图所示,这是一颗最小度数为3的B树,即他的关键字个数为2~5个。
插入关键字B,在根节点由于(B < G)往进入G的左节点,到达叶节点后添加至A与C关键字之间。
插入关键字Q:
  1. 在根节点,由于P < Q 而且 Q < X,进入P与X之间的子节点
  2. 发现该子节点是满的,则进行分裂,把关键字T上升到父节点,原子节点分为RS与UV,分为在T关键字的左右
  3. 由于Q < T,于是进入T的左子节点
  4. 在RS叶节点中找到对应位置并加入
插入关键字L:
  1. 发现根节点是满的,分裂根节点,上移P
  2. L < P 进入P的左子节点
  3. G < L < M,进入G与M关键字间的节点
  4. 在叶节点的相应位置中插入
插入关键字F:
  1. F < P,进入P的左子节点
  2. F < G,进入G的左子节点
  3. 发现满的节点,分裂,上移C
  4. F > C,进入C的右子节点
  5. 在叶节点的相应位置中插入
 

4.B树的删除

讲完了B树的插入操作,我们再来讲讲B树的删除操作。
对于删除操作,我们必须保证每个节点在删除前必须至少有t(最小度数)个关键字。
首先我们把要删除的关键字(假设为k)分两种情况:
  • 关键字k在叶节点中:直接删除
  • 关键字k在内部节点中,分三种情况:
    • k的左子节点拥有t个关键字,则把k的左子节点的最后一个关键字(假设为j)上移到父节点,然后递归的删除j
    • k的右子节点拥有t个关键字,则把k的右子节点的第一个关键字(假设为l)上移到父节点,然后递归的删除l
    • k的左右子节点都只有t-1个关键字,则把k下降与左右子节点合并成一个拥有2t-1个关键字的节点,然后递归的删除k
然后我们再定义一些在寻找删除节点路上的操作:如果在寻找删除节点的路上,我们发现某个节点关键字数只有t-1个关键字,则分两种情况:
  1. 看该节点的相邻兄弟节点是否含有至少t个关键字,如果是则向相邻的兄弟节点“借一个关键字”(一该节点的左节点为例:把左节点的最后一个关键字上升至父节点,然后父节点位置的节点下移到关键字个数为t-1的节点上)
  2. 如果该节点相邻的兄弟节点都只含有t-1个关键字,则选择一个兄弟节点合并,并把两兄弟之间的父节点下移
下面我们来看一个B树删除的例子:
B树的初始状态如图,这是一颗最小度数为3的B树,即每个节点拥有2~5个关键字。
删除F操作:
  1. F < P,进入P的左子节点
  2. C < F < G,进入C与G之间的子节点
  3. 在叶节点中删除F
删除M操作:
  1. M < P,进入P的左子节点
  2. 在内部节点中发现M,查看M的左子节点JKL,拥有3个关键字,则把最后一个关键字L上升至M的位置,递归的删除L
  3. 节点JKL是叶节点,直接删除L即可
删除G操作:
  1. G < P,进入P的左子节点
  2. 在内部节点中发现G,查看G的左右子节点均只有2个关键字(不足最小度数3个),下降G关键字并合并其左右子节点
  3. 节点DEGJK为叶节点,直接删除G即可
删除D操作:
  1. D < P,进入P的左子节点
  2. 发现内部节点CL只有2个关键字(不足最小度数3个),其兄弟节点也只有2个关键字,下降父节点P,与兄弟节点一起合并成一个节点
  3. 由于C < D < L,进入C与L间的子节点
  4. DEJK节点是叶节点,直接删除D即可
删除B操作:
    1. B < C,进入E的左子节点
    2. 发现节点AC只有两个关键字,其兄弟节点EJK有三个关键字,则E上移到父节点,C下移到子节点,变为节点ABC
    3. 节点ABC为叶节点,直接删除B即可

算法导轮之B树的学习的更多相关文章

  1. 从K近邻算法谈到KD树、SIFT+BBF算法

    转自 http://blog.csdn.net/v_july_v/article/details/8203674 ,感谢july的辛勤劳动 前言 前两日,在微博上说:“到今天为止,我至少亏欠了3篇文章 ...

  2. Java数据结构和算法(一)树

    Java数据结构和算法(一)树 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 前面讲到的链表.栈和队列都是一对一的线性结构, ...

  3. python常用算法(5)——树,二叉树与AVL树

    1,树 树是一种非常重要的非线性数据结构,直观的看,它是数据元素(在树中称为节点)按分支关系组织起来的结构,很像自然界中树那样.树结构在客观世界中广泛存在,如人类社会的族谱和各种社会组织机构都可用树形 ...

  4. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  5. 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

    树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构.    a.树是n ...

  6. 数据结构与算法(九):AVL树详细讲解

    数据结构与算法(一):基础简介 数据结构与算法(二):基于数组的实现ArrayList源码彻底分析 数据结构与算法(三):基于链表的实现LinkedList源码彻底分析 数据结构与算法(四):基于哈希 ...

  7. Java数据结构和算法(二)树的基本操作

    Java数据结构和算法(二)树的基本操作 数据结构与算法目录(https://www.cnblogs.com/binarylei/p/10115867.html) 一.树的遍历 二叉树遍历分为:前序遍 ...

  8. 用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成“***”就可 ...

  9. 第15个算法-实现 Trie (前缀树)(LeetCode)

    解法代码来源 :https://blog.csdn.net/whdAlive/article/details/81084793 算法来源:力扣(LeetCode)链接:https://leetcode ...

随机推荐

  1. SpringBoot的配置文件加载顺序和使用方式

    1.bootstrap.properties bootstrap.properties 配置文件是由"根"上下文优先加载,程序启动之初就感知 如:Spring Cloud Conf ...

  2. linux下Tab及shell 补全python

    Python自动补全 Python自动补全有vim编辑下和python交互模式下,下面分别介绍如何在这2种情况下实现Tab键自动补全. vim python自动补全插件:pydiction 可以实现下 ...

  3. 小技巧-ASP.Net session保存在数据库服务器

    引用博客:http://www.cnblogs.com/lykbk/archive/2013/01/13/hf576856868.html web Form 网页是基于HTTP的,它们没有状态, 这意 ...

  4. php+MySql实现登录系统与输出浏览者信息功能

    这篇文章主要介绍了php+MySql实现登录系统与输出浏览者信息功能 的相关资料,需要的朋友可以参考下   本系统,与之前在<ASP 连接Access数据库的登陆系统>(点击打开链接)一文 ...

  5. 区块链3.0:拥抱EOS

    EOS是当下最火的区块链技术,被社会广泛看好为下一代区块链3.0.不同于以太坊的学习,EOS的主语言是C++,本文作为EOS研究的首篇文章,重点介绍EOS的创新点,它的周边生态,各种概念原理的解释,以 ...

  6. 深入理解.net - 1.继承的本质

    最近偶然看到这个博客你必须知道的.net,作者6的飞起啊,干货十足,还是07年写的...写的也很赞,评论更精彩,在此强烈推荐一波,看的感觉就像沙漠里发现了绿洲一样,很兴奋,意犹未尽,迫不及待的看完一篇 ...

  7. 使用Markup解析xml文件

    1:怎么获取Markup.cpp 和 Markup.h 首先到http://www.firstobject.com/dn_markup.htm链接下,下载Release 11.5 zip (579k) ...

  8. javascript实现有限状态机

    1.状态机描述 简单说,有限状态机是一种模型,模型都用来模拟事物,能够被有限状态机这种模型模拟的事物,一般都有以下特点: 1)可以用状态来描述事物,并且任一时刻,事物总是处于一种状态: 2)事物拥有的 ...

  9. Vim+Vundle+YouCompleteMe 安装

    这段时间在Centos 7上开发c++程序,想为vim安装YouCompleteMe插件,参照几个博客无果,果断上官网找解决方案.功夫不负苦心人,终于搞定. 学习东西还是要多上官网. 下面送上本次的收 ...

  10. [LeetCode] Prime Number of Set Bits in Binary Representation 二进制表示中的非零位个数为质数

    Given two integers L and R, find the count of numbers in the range [L, R] (inclusive) having a prime ...