本文虽然用多路查找树引入,但是主角是B树,文中提到的2-3树,2-3-4树都是特殊的B树。
B树是学习数据结构以来,第一个考虑了硬盘的数据结构。之前所有的数据结构,包括线性表,各种树,图,都是在内存中进行各种操作。B树,其存储量之大,使得B树上部分结点里存储的数据记录存储在硬盘中,而不是在内存中。
文章目录
外存的查找性能主要取决于 读取次数,所以设计中主要考虑B树的层次和平衡
引入
电脑的内存使用硅材料制作,一般只有几个G,多插些内存条可以做到更高,但是硬盘外存一般使用磁盘,造价更便宜,所以一般都有几百个G甚至一两个TB。内存的造价比硬盘贵大约100倍,但是速度比硬盘快约100倍。
如果把人看做一种生物计算机,那么大脑内的记忆区就像电脑的内存,而纸或其他存储介质就相当于外存。使用记忆就像是电脑使用内存,比较快,但是容量有限;而查阅书籍等外存虽然慢些,但是存储空间多得多。
之前讨论的查找算法,或者用于查找的数据结构(比如二叉查找树,AVL树等)都是在内存中处理数据的,所以之前考虑的时间复杂度都是只考虑了在内存中运行的时间复杂度,比如查找某元素需要的比较操作的次数。
但是如果数据很大很大,超出了内存处理能力,比如数据库以及硬盘中的文件,拥有千万级别的记录,这时候必须还要考虑从硬盘等存储设备中存取数据的时间复杂度,所以我们要考虑访问外存的次数,以及单次访问外存的时间。
外存的查找性能主要取决于读取次数,读取磁盘上万次和几十次的两个算法有天壤之别。所以,我们必须设计专门的数据结构来处理这种需要访问外存的情况。
多路查找树:每个结点可有多个孩子,且可存多个元素
为什么要用一个结点存多个元素:减少外存访问次数
树的高度非常大,则需要的存储空间也更大,内存存不下,所以就必须存在外存中,于是就增多了外存访问次数。
多路查找树的四种特殊形式
2-3树(3阶B树,最简单的B树)
2-3树,2-3-4树都是特殊的B树,但是现实中基本不用他们,讲解他俩纯粹是为了带领新人理解B树的原理,明白B树到底想干嘛,到底是个什么思想,什么出发点。从后面讲了B树后就明白,实际应用中,我们希望B树的阶数m越大越好,最好是和硬盘一页的大小匹配起来,这样一次可以从硬盘中读取整页数据并存入B树,需要访问外存的次数就少了。这里的3阶4阶B树真心是为了理解B树,所以根本都不写他们的代码实现,因为用不着。
先看个例子
定义和性质
即结点要么没孩子,要么有2个孩子,要么有3个孩子的树,就是不能只有一个孩子,哈哈。
2结点和3结点
2结点:
- 没孩子
- 有俩孩子
- 只能存一个元素
3结点:
- 没孩子
- 有仨孩子
- 可存两个元素,两个元素的较小者排在左侧
2-3树的所有叶子在同一层
难点:插入和删除操作
因为插入或删除一个结点后会对其他结点产生连锁反应,要保证插入或删除后仍然是一棵2-3树,即所有叶子仍然在同一层次,且仍然是有序的,就比较复杂。
新结点的插入操作(够酸爽,总共5种情况)
动不动就可能要升级某个结点(从2结点升级为3结点),并且可升级的结点可能需要挨个往树的高层找;
还可能要拆分已有结点;
还可能要占用已有结点的位置,然后给已有结点重新找地方;
这些骚操作啊,眼花缭乱,够灵活的。
具体地,插入可以分为三种情况。
- 给空树插入一个2结点(简单)
没的说,注意2-3树插入新结点,默认插入2结点,不会直接插入3结点,但是后面有可能需要把2结点升级为3结点,即3结点都是通过升级得到的,不是直接就新建3结点。
2. 插入元素到一个2结点叶子上(较简单)
即该节点是一个没孩子的2结点,这时候,办法是:把这个2结点叶子升级为一个3结点叶子。
如下图,要把3插入到树中,3小于8&