when ? why ? how ? what ?

平衡二叉树其查找的时间复杂度是 O(log2N)与树的深度相关,那么降低树的深度自然会提高查找效率。

如果我们要操作的数据集非常大,大到内存已经没法处理了怎么办呢?如数据库中的上千万条记录的数据表、硬盘中的上万个文件等。在这种情况下,对数据的处理需要不断从硬盘等存储设备中调入或调出内存页面。

一旦涉及到这样的外部存储设备,关于时间复杂度的计算就会发生变化,访问该集合元素的时间已经不仅仅是寻找改元素所比较次数的函数,我们必须考虑硬盘等外部存储设备的访问时间以及将会对该设备做出多少次单独访问

我们从外存储器中读取信息的步骤,简单来分,大致有两步:

  1. 找到存储这个数据所对应的磁盘页面,这个过程是机械化的过程,需要依靠磁臂的转动,找到对应磁道,所以耗时长。
  2. 读取数据进内存,并实施运算,这是电子化的过程,相当快。

为什么需要 B 树?

在一个拥有几十万个文件的磁盘中查找一个文本文件,你设计的算法需要读取磁盘上万次还是读取几十次,这是有本质差异。此时,为了降低对外存设备的访问次数,我们就需要新的数据结构(B 树)来处理这样的问题

之前谈的树,都是一个结点可以有多个孩子,但它自身只存储一个元素。二叉树限制更多,结点最多只能有两个孩子。

问题来了? 在元素非常多的时候,要么树的度非常大(结点拥有子树的个数的最大值),要么树的高度非常大,甚至两者都必须足够大才行。这就使得内存存取外存次数非常多,这显然成了时间效率上的瓶颈,这迫使我们要打破每一个结点只存储一个元素的限制,为此引入了多路查找树


多路查找树

什么是多路查找树?

多路查找树(muitl-way search tree),其每一个结点的孩子数可以多于两个,且每个结点出可以存储多个元素。由于它是查找树,所有元素之间存在某种特定的排序关系。

B 树

B 树是一种平衡的多路查找树,2-3树和2-3-4树都是 B 树的特例。结点最大孩子的数目称为 B 树的阶(order),因此,2-3 树是 3 阶 B 树,2-3-4 树是 4 阶 B 树 。

一个 m 阶的 B 树具有如下属性:

  1. 如果根结点不是叶结点,则其至少有两棵子树
  2. 每一个非根的分支结点都有 k-1 个元素和 k 个孩子,其中 ⌈m/2⌉ <= k <=m
  3. 所有的叶子节点都位于同一层
  4. 所有分支结点包含下列信息数据(n,A0,K1,A1,K2,A2....,Kn,An),其中:Ki(i=1,2,3,...n)为关键字,且 Ki < Ki+1(i=1,2,....,n-1);Ai(i=0,2,....n)为指向子树根结点的指针,且指针 Ai-1 所指子树中所有结点的关键字均小于 Ki(i=1,2,....,n),An所指子树中所有结点的关键字均大于 Kn,n(⌈m/2⌉-1<= n <=m-1)为关键字的个数(或n+1为子树的个数)。

2-3-4树

下图灰色方块表示当前结点元素的个数。

如果内存和外存交换数据次数频繁,会造成了时间效率上的瓶颈,那么 B 树结构怎么就可以做到减少次数呢?

外存比如硬盘,是将所有的信息分割成相等大小的页面,每次硬盘读写的都是一个或多个完整的页面,对于一个硬盘来说,一页的长度可能是 211 或 214 个字节。

在一个典型的 B 树应用中,要处理的硬盘数据量很大,因此无法一次全部装入内存。因此我们会对 B 树 进行调整,使得 B 树的阶数 (或结点的元素)与硬盘存储的页面大小匹配。比如一棵 B 树的阶位 1001(即一个结点包含 1000 个关键字),高度为 2,它可以存储超过 10 亿个关键字,我们只要让根结点持久地保留在内存中,那么在这棵树上,寻找某一个关键字至多需要两次硬盘的读取即可。

通过这种方式,在有限内存的情况下,每一次磁盘的访问我们都可以获取最大数量的数据。由于 B 树每结点可以具有比二叉树多得多的元素,所以与二叉树的操作不同,它们减少必须访问结点和数据块的数量,从而提高了性能。可以说,B树的数据结构就是为内外存的数据交互准备的。

对于有n个关键字的m阶B-树,从根结点到关键字所在结点的路径上路过的结点数不超过:

B+树

为什么会产生 B+ 树呢?

肯定是 B 树有些缺陷,有些需求然后就产生的 B+ 树。

如上图的 2-3 树,要是你想查找 3~11 范围的元素,中序遍历 页面 5 -> 页面 2 ->页面 6 -> 页面 1 ->页面 7,查找很麻烦,看看 B+树

当找到查找下限 3 后,通过链表指针可以查找到 11,这样会快很多。

在 B 树中,每一个元素在该树中只出现一次,有可能在叶子结点上,也有可能在分支结点上。而在 B+ 树中,出现在分支结点中的元素会被当作它们在该分支结点位置的中序后继者(叶子结点)中再次列出。另外,每一叶子结点都会保存一个指向后一叶子结点的指针。

卫星数据:指的是索引元素所指向的数据记录,比如数据库中的某一行。

B+ 树的特征:

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

B+ 树的优势

  1. B+ 树的中间结点没有卫星数据。所有以同样大小的磁盘可以容纳更多结点元素,这就意味着,数据量相同的情况下,B+ 树的结构比 B- 树更加“矮胖”,因此查询是 IO次数也更少。
  2. B- 树查找性能不稳定(最好情况只查根结点,最坏情况查到叶子结点),而B+ 树每次查找都是最稳定的。
  3. 所有叶子节点形成有序链表,便于范围查询。如查找学小18~22岁的学生人数,我们可以通过根结点触发找到第一个18岁学生,然后再在叶子结点按顺序查找到符合范围的所有记录

总结

参考

大话数据结构

https://www.sohu.com/a/156886901_479559

B树是为实现高效的磁盘存取而设计的多叉平衡搜索树。这个概念在文件系统,数据库系统中非常重要。数据库中的索引就用了B树或B+树。

有什么问题欢迎指出,十分感谢!

B树、B+树的更多相关文章

  1. BZOJ 3110: [Zjoi2013]K大数查询 [树套树]

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6050  Solved: 2007[Submit][Sta ...

  2. BZOJ4170 极光(CDQ分治 或 树套树)

    传送门 BZOJ上的题目没有题面-- [样例输入] 3 5 2 4 3 Query 2 2 Modify 1 3 Query 2 2 Modify 1 2 Query 1 1 [样例输出] 2 3 3 ...

  3. Atitit 常见的树形结构 红黑树  二叉树   B树 B+树  Trie树 attilax理解与总结

    Atitit 常见的树形结构 红黑树  二叉树   B树 B+树  Trie树 attilax理解与总结 1.1. 树形结构-- 一对多的关系1 1.2. 树的相关术语: 1 1.3. 常见的树形结构 ...

  4. bzoj3262: 陌上花开(树套树)

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  5. bzoj3295: [Cqoi2011]动态逆序对(树套树)

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  6. BZOJ 3110 k大数查询 & 树套树

    题意: 有n个位置,每个位置可以看做一个集合,现在要求你实现一个数据结构支持以下功能: 1:在a-b的集合中插入一个数 2:询问a-b集合中所有元素的第k大. SOL: 调得火大! 李建说数据结构题能 ...

  7. HDU 5877 dfs+ 线段树(或+树状树组)

    1.HDU 5877  Weak Pair 2.总结:有多种做法,这里写了dfs+线段树(或+树状树组),还可用主席树或平衡树,但还不会这两个 3.思路:利用dfs遍历子节点,同时对于每个子节点au, ...

  8. BZOJ 3110 树套树 && 永久化标记

    感觉树套树是个非常高深的数据结构.从来没写过 #include <iostream> #include <cstdio> #include <algorithm> ...

  9. 字符串 --- KMP Eentend-Kmp 自动机 trie图 trie树 后缀树 后缀数组

    涉及到字符串的问题,无外乎这样一些算法和数据结构:自动机 KMP算法 Extend-KMP 后缀树 后缀数组 trie树 trie图及其应用.当然这些都是比较高级的数据结构和算法,而这里面最常用和最熟 ...

  10. 学习笔记--函数式线段树(主席树)(动态维护第K极值(树状数组套主席树))

    函数式线段树..资瓷 区间第K极值查询 似乎不过似乎划分树的效率更优于它,但是如果主席树套树状数组后,可以处理动态的第K极值.即资瓷插入删除,划分树则不同- 那么原理也比较易懂: 建造一棵线段树(权值 ...

随机推荐

  1. PX4/Pixhawk---高速成为开发人员(Windows)

    1 高速成为开发人员新手教程(翻译)---官方 1.1 编译环境之版本号控制系统 (1)安装MSysGIT 安装完毕后,配置GIT. 安装注意     安装过程中除了以下一步外,其它的步骤都採用默认安 ...

  2. 【转】Intent传递数据时,可以传递哪些类型数据?

    在Android应用的开发中,如果我们需要在不同的模块(比如不同的Activity之间)之间传递数据,通常有以下两种方法:1. 利用Intent对象携带数据通过查询Intent/Bundle的API文 ...

  3. 换npm yarn的源让install超时去死吧

    安装npm install时,长时间停留在fetchMetadata: sill mapToRegistry uri http://registry.npmjs.org/whatwg-fetch处, ...

  4. WebSocket 网页聊天室的实现(服务器端:.net + windows服务,前端:Html5)

    websocket是HTML5中的比较有特色一块,它使得以往在客户端软件中常用的socket在web程序中也能轻松的使用,较大的提高了效率.废话不多说,直接进入题. 网页聊天室包括2个部分,后端服务器 ...

  5. 洛谷P2516 [HAOI2010]最长公共子序列

    题目描述 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X="x0,x1,-,xm-1",序列Y=& ...

  6. tinymce 出现 Uncaught (in promise) TypeError: ae(...).createObjectURL is not a function

    需要引入两个JS文件:jQuery.tinymce.min.js 和 tinymce.min.js <script type="text/javascript" src=&q ...

  7. canvas做的一个写字板

    <!DOCTYPE html><html><head><title>画板实验</title> <meta charset=" ...

  8. 【BZOJ1483】[HNOI2009]梦幻布丁(平衡树启发式合并+并查集)

    题目: BZOJ1483 分析: (这题码了一下午,码了近250行,但是意外跑的比本校各位神仙稍快,特写博客纪念) 首先能看出一个显然的结论:颜色段数只会变少不会变多. 我们考虑用并查集维护区间,对于 ...

  9. Select2插件ajax方式加载数据并刷新页面数据回显

    今天在优化项目当中,有个要在下拉框中搜索数据的需求:最后选择使用selec2进行开发: 官网:http://select2.github.io/ 演示: 准备工作: 文件需要引入select2.ful ...

  10. react杂记

    React webpack+react (hello world) 项目结构: src: app.js main.js package.json webpack_dev_config.js 需要安装包 ...