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. python实现自动重启本程序的方法 技术的漩涡

    python实现自动重启本程序的方法 http://www.jb51.net/article/69174.htm import requests, time url_l = []with open(' ...

  2. CDOJ 1330 柱爷与远古法阵(高斯消元)

    CDOJ 1330 柱爷与远古法阵(高斯消元) 柱爷与远古法阵 Time Limit: 125/125MS (Java/Others)     Memory Limit: 240000/240000K ...

  3. POJ3090 Visible Lattice Points 欧拉函数

    欧拉函数裸题,直接欧拉函数值乘二加一就行了.具体证明略,反正很简单. 题干: Description A lattice point (x, y) in the first quadrant (x a ...

  4. [CF391E2]Three Trees

    https://zybuluo.com/ysner/note/1246822 题面 有三棵树,建两条边让他们相连,最大化所有点对距离之和. \(40pts\ n\leq1000\) \(100pts\ ...

  5. JSP-Runoob:JSP 自定义标签

    ylbtech-JSP-Runoob:JSP 自定义标签 1.返回顶部 1. JSP 自定义标签 自定义标签是用户定义的JSP语言元素.当JSP页面包含一个自定义标签时将被转化为servlet,标签转 ...

  6. PCB MS SQL 标量函数与表值函数(CLR) 实现文件与目录操作

    一.C#写SQL SERVER(CLR)实现文件操作 标量函数: 文件移动 ,复制,检测文件存在,写入新文件文本,读取文本,创建目录,删除目录,检测目录是否存在 /// <summary> ...

  7. 慕课网6-2 作业:js实现轮播特效

    小伙伴们,掌握了JavaScript的语法.流程控制语句.内置对象以及DOM和BOM的知识,运用所学知识完成如下图所示的交互效果——轮播图.效果图如下: 具体交互效果图参考gif动态效果图,gif效果 ...

  8. JavaScript入门二

    ******函数****** **函数定义** //普通函数定义 function f1() { console.log("Hello word!") } //带参数的函数 fun ...

  9. 关于BUG

    1.BUG的理解 2.提高BUG report的技巧

  10. vue 中展示PDF内容

    vue 中展示PDF内容 不久前有个需要改的需求,以前是直接根据链接让用户下载对应pdf文件来查看,最主要是给用户查看,然而这种并不是很安全的,其他用户可以进行下载或者使用pdf链接分享给其他人,所以 ...