文章目录

  • 前言
  • B- 树
    • 查找
    • 插入
    • 删除
  • B+ 树
    • 查找
    • 范围查找
  • 总结
  • 参考资料

前言

从算法逻辑上讲二叉查找树的查找和插入操作效率都已经很高,但是在实际应用中由于我们不能将整个索引表加载到内存,只能逐一加载每个磁盘页,这里的磁盘页就对应着索引树的节点。因此我们要将原本“瘦高”的树结构变得“矮胖”,从而减少磁盘IO的次数。

B- 树

B-树是一种多路平衡查找树,是对2-3树的一个扩展。一个m阶的B树(m的大小取决于磁盘页的大小)具有如下几个特征:

  • 根结点至少有两个子女。
  • 每个中间节点都包含k-1个元素和k个孩子,其中 k ∈ [m/2, m]
  • 每一个叶子节点都包含k-1个元素,其中 k ∈ [m/2, m]
  • 所有的叶子结点都位于同一层。
  • 每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域分划。

查找

下图以一个3阶B-树为例,第一次磁盘IO并在内存中和9比较:

第二次磁盘IO并在内存中和2、6比较:

第三次磁盘IO并在内存中和3、5比较:

单从比较次数来说B树相比二叉查找树并不占优势,但由于节点中存储着多个元素,因此它的磁盘IO次数比二叉查找树少很多,而内存中的比较耗时几乎可以忽略,因此查找性能也就比二叉查找树更好。

插入

以插入元素4为例,自顶向下查找4的节点位置,发现4应当插入到节点元素3,5之间,而由于此B-树是3阶的,每个节点最多能有2个元素,因此该节点无法再增加,而其父节点也含有两个元素,根节点只有一个元素。

于是拆分节点3,5与节点2,6,让根节点9升级为两元素节点4,9。节点6独立为根节点的第二个孩子。

删除

以删除元素11为例,先自顶向下查找元素11的节点位置。

删除11后,节点12只有一个孩子,不符合B树规范。因此找出12,13,15三个节点的中位数13,取代节点12,而节点12自身下移成为第一个孩子(左旋操作)。


B+ 树

B+树是B-树的一个变体,有着比B-树更高的查询性能。一个m阶的B+树(m的大小取决于磁盘页的大小)具有如下几个特征:

  • 有k个子树的中间节点包含有k个元素(B-树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。
  • 所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。
  • 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。

注意,根节点的最大元素(上图中是15)等同于整个B+树的最大元素;由于父节点的元素都出现在子节点,因此所有叶子节点包含了全量元素信息,并且每一个叶子节点都带有指向下一个节点的指针,形成了一个有序链表。

查找

在B-树中,无论中间节点还是叶子节点都带有卫星数据(索引元素所指向的数据记录),而B+树中间节点没有卫星数据,只有索引,这就意味着同样大小的磁盘页可以容纳更多节点元素,在相同的数据量下,B+树更加“矮胖”,IO操作更少。


下图以查找元素3为例,第一次磁盘IO:

第二次磁盘IO:

第三次磁盘IO:

B+树除了比B树更加“矮胖”这一点不同外,由于B+树的查询必须最终查找到叶子节点,而B-树中无论匹配元素处于中间节点还是叶子节点只要找到匹配元素即可,所以B+树的查找性能是稳定的,而B-树的查找性能不稳定(最好情况是只查根节点,最坏情况是查到叶子节点)。

范围查找

由于B+树的叶子节点构成了一条有序链表,因此B+树的范围查找比B-树简单得多,下面以查询范围为3到11的元素为例。

自顶向下,查找到范围的下限3:

通过链表指针,遍历到元素6、8:

通过链表指针,遍历到元素9、11,遍历结束:

总结

为了减少磁盘IO的次数,必须降低树的深度,将“瘦高”的树变得“矮胖,使得磁盘页可以容纳更多节点元素,因此出现了B-树。B+树是B-树的变体,相比B-树有以下优势:

  • 单一节点存储更多的元素,使得查询的IO次数更少。
  • 所有查询都要查找到叶子节点,查询性能稳定。
  • 所有叶子节点形成有序链表,便于范围查询。

参考资料

  • 漫画:什么是B-树?
  • 漫画:什么是B+树?

常用查找算法之B/B+树相关推荐

  1. C++ STL 常用查找算法

    C++ STL 常用查找算法 adjacent_find() 在iterator对标识元素范围内,查找一对相邻重复元素,找到则返回指向这对元素的第一个元素的迭代器.否则返回past-the-end. ...

  2. C++STL常用查找算法

    C++STL常用查找算法 学习目标 算法简介 find 功能描述 函数原型 示例 总结 find_if 功能描述 函数原型 示例 总结 adjacent_find 功能描述 函数原型 示例 总结 bi ...

  3. STL算法——常用查找算法(find、find_if、adjacent_find、binary_search、count、count_if)

    5.2 常用查找算法 学习目标: 掌握常用的查找算法 算法简介: find //查找元素 find_if //按条件查找元素 adjacent_find //查找相邻重复元素 binary_searc ...

  4. C++实现常用查找算法

    在日常编程和面试中,查找算法和排序算法需要非常熟练.本文用C++语言的语法来写常用的查找算法:顺序查找,二分查找, 一.顺序查找 1.1基本思想(有序无序皆可以) 1 从表中的第一个元素开始,依次与关 ...

  5. java 二分搜索获得大于目标数的第一位_程序员常用查找算法(顺序、二分、插值、分块、斐波那契)...

    顺序查找 基本思想 属于线性查找和无序查找,从一端开始顺序扫描,直到找到与目标值value相等的元素. 这是最基本的查找方法,也是时间复杂度最高的查找算法. 在数据过多时,这种方法并不适用. 代码实现 ...

  6. c语言中的常用查找算法

    1.顺序查找: 概念:按照顺序,从第一个元素遍历到最后一个元素,找到就返回元素下标:下面的代码可以帮助你更好的理解: int main {int arr[]={1,2,3,4,5,6,7};int k ...

  7. C++常用查找算法总结(一)

    查找是在大量的信息中寻找一个特定的信息元素,在计算机应用中,查找是常用的基本运算,例如编译程序中符号表的查找,字段的查找,等等. 1.查找算法总结 (1). 最容易理解的查找算法,顺序查找法 说明:顺 ...

  8. 常用查找算法(顺序、折半、二叉树、哈希、分块)介绍

    一.顺序查找  条件:无序或有序队列. 原理:按顺序比较每个元素,直到找到关键字为止. 时间复杂度:O(n) 二.二分查找(折半查找)  条件:有序数组 原理:查找过程从数组的中间元素开始,如果中间元 ...

  9. C++ 常用查找算法

    #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include <algorithm> using namespace ...

最新文章

  1. python的类属性和方法_Python中类属性、实例属性和实例方法的区别
  2. Android stadio Switch repository Android stadio切换仓库
  3. SpringMVC的数据转换、格式化和数据校验
  4. python dd 合并二进制文件_马克的Python学习笔记#数据编码与处理 5
  5. 搜索引擎Elasticsearch,这篇文章给讲透了(建议收藏)
  6. diff 比较文件异同命令
  7. iapp软件库源码分享
  8. Office安装时闪退,用Windows Installer Cleanup彻底卸载 或 注册表清理解决
  9. 编写树莓派引脚驱动代码
  10. 微信与企业微信的十个区别
  11. 【寒江雪】空间中的点线和面
  12. 基础知识(一)WPF与 Blend的关系,以及Blend如何快速生成xaml代码,即Path数据。
  13. OSChina 周三乱弹 —— 致力于做一名优秀的女程序员鼓励师
  14. 放不下的原理_通俗易懂,几张图看懂大数据存储和计算原理
  15. 什么是PO设计(封装)?
  16. 四川大学计算机考研专业参考书目,四川大学计算机技术(专业学位)研究生考试科目和考研参考书目...
  17. BIOS功能调用表格
  18. javascript--浅谈函数与闭包
  19. windows 7 IE临时文件夹地址?
  20. 限时抢购php购广告语,网络购物博览会广告语

热门文章

  1. “IT学子成长指导”专栏及文章目录 —贺利坚
  2. JQuery写农场的小游戏
  3. 被迫营业的网店订单管理系统!表弟的毕设!这也太简单了!
  4. 大学计算机uml ppt,南京大学计算机科学与技术系Object-OrientedSoftwareEngineeringUnifiedModelingLanguageUML幻灯片资料.ppt...
  5. 汤力嘉:秒拍-10秒拍大片!
  6. 详解JS深拷贝与浅拷贝
  7. 优秀前端工程师简历收集
  8. 电属于可再生能源吗?
  9. 计算机组成原理1:计算机系统概述
  10. 关于 GRB YUV 介绍