链接:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
可以点击 Indexing 下的 B Trees 和 B+ Trees 去学习。
对 B 树的需求随着访问物理存储介质(如硬盘)的时间减少而增加。辅助存储设备速度较慢,容量较大。需要这种类型的数据结构来最大限度地减少磁盘访问。
其他数据结构如二叉搜索树、avl 树、红黑树等只能在一个节点中存储一个键。如果必须存储大量键,则此类树的高度将变得非常大,并且访问时间也会增加。
但是,B 树可以在单个节点中存储许多键,并且可以有多个子节点。这大大降低了高度,允许更快的磁盘访问。
B- 树和 B 树都指的都是 B 树,此外还有 B+ 树。
可以把 B 树理解为一个有序的多叉树。
满足下列要求的 m 阶树:
(1)每个节点最多拥有 m 个孩子结点(即至多有 m-1 个关键字)
(2)每个结点的结构为
第一个位置的 n 用来表示结点有多少个关键字。
Pn 表示子树的指针,顺着指针可以找到子树的位置。
k 表示关键字。
例如:m = 4 的 4 阶 B 树
(3)除根节点外,其他结点至少有 m / 2 (向上取整)个孩子结点。
(4)若根节点不是叶子结点,则根节点至少有两个孩子结点。
(5)所有叶子结点都在同一层上,即B树是所有结点的平衡因子均等于0的多路查找树。
(6)除根节点外,其他节点都包含 n 个 key ,其中 [m/2]-1<=n<=m-1。
已知一棵三阶 B 树如下图所示,给出在 B 树中查找 37 的过程。
查找37,根节点是48,48>37,看48的左子树,25<37,看25的右子树,37=37。
那具体是怎么查找的呢??
首先来了解一下操作系统的磁盘预读。
磁盘预读:
4k
或者16k
,我们在数据交互时,可以取页的整数倍
来进行读取。CPU要先把数据加载到内存中然后磁盘从内存中读取数据。
比如说这个 word 文档右击查看它的属性,虽然大小是46.9KB,但是占用空间是48KB,这是4K的整数倍,也就是磁盘加载数据到内存中都是datapage的整数倍。
我们可以结合操作系统知识理解 B 树的查找过程。
键值:表中的主键
指针:存储子节点的信息
数据:表记录中除主键外的数据
B树的每一个结点都是放在磁盘块里的,且一般规定磁盘块大小是16K
假如要在图中找一个关键字为28的数据:
首先把磁盘上的这个块加载到内存里,16<28,34>28,找到磁盘块1的p2,这是进行的第一次IO。
然后顺着磁盘块1的p2找到磁盘块3,再把磁盘块3加载到内存里面,然后28<25,28>31,找到磁盘块3的p2了。这是第二次IO。
然后顺着磁盘块3的p2找到磁盘块8,再把磁盘块8加载到内存里,28=28,返回关键字28对应的data。这是第三次IO。
现在这个B树总共有三层,每个结点 datapage 是 16k ,假设指针和关键字不占用 datapage (占用很小),每个 data 占用 1k ,所以三层 B 树可以存储的 data 个数是16*16*16=2^12=4096
条,还是在不考虑指针和关键字的 datapage 情况下的。所以如果要是存 10000 条数据的时候怎么办呢?或许你想到的是再给 B 树加一层,确实可以这样存储 10000 条数据,但是这样的话层数增多了,查找数据就要再多一次 IO 操作,再多一次 IO 操作那查找的速度不就又慢了吗?
那为什么 B 树要存储更多数据只能增加层数呢?因为存储空间都用来放 data 了,如果只存指针和关键字的话所占用的磁盘空间是非常小的,所以我们可以把 data 都放在叶子结点上,非叶子结点只存指针和关键字,可以提升查找速度,这就是 B+ 树。
B+ 树结构长这样:
datapage 还是 16k ,假设每对指针和关键字(例如 上图磁盘块1的p1 ,28 )只占 10 个字节,那么一个结点可以存16000/10=1600
个数据,三层结构可以存储 1600*1600*1600
千万级数据,存储的数据是非常多的。
已知一棵 5 阶(度)B 树如下图所示,给出在B树中删除 80、200、180、50、140 的过程。
要将删除非叶子节点的关键字转换为删除叶子节点关键字。在 B 树性质里,m阶树,除根节点外,其他节点都包含 n 个 key ,其中 [m/2]-1<=n<=m-1
如果节点删除一个关键字后,节点关键字依然大于 [m/2]-1个,那么不需要去做任何的变动直接删除就可以;如果删除关键字后小于 [m/2]-1个key,那么就需要让下一个节点的关键字补上来
在 B 树中删除 80、200、180、50、140 的过程如下: