一、红黑树
二叉树具有搜索速度快的特点,但是在极端情况下(比如二叉树的最小或最大值在根节点)那么这种二叉树的查询速度就接近于线性结构的查询速度,为了避免这种问题,发明了平衡二叉树(AVL),平衡二叉树的特点是根节点的左边和右边的子树的高度差不可能大于一,但是每次插入或删除时就需要对整棵树进行旋转,大大影响了效率,在这种情况下,红黑树应运而生,红黑树的特点是弱平衡,但在插入或删除节点的效率上面大大超过了平衡树。
红黑树通过以下的定义来实现弱平衡:
- 待插入的节点默认是红色的
- 根节点是黑色的
- 红色节点的儿子节点必须全部是黑色的(任意两个红色的节点无法相连)
- 叶子节点必须是黑色的
- 从任意节点到其他叶子节点的简单路径都包括相同数量的黑色节点
为什么红黑树的最短路径的长度不超过最长路径的两倍?
当某条路径最短时,这条路径必然都是由黑色节点构成。当某条路径长度最长时,这条路径必然是由红色和黑色节点相间构成(性质3限定了不能出现两个连续的红色节点)。而性质5又限定了从任一节点到其每个叶子节点的所有路径必须包含相同数量的黑色节点。此时,在路径最长的情况下,路径上红色节点数量 = 黑色节点数量。该路径长度为两倍黑色节点数量,也就是最短路径长度的2倍。
二、b树
2.1简介
一个m阶的B树具有如下几个特征:B树中所有结点的孩子结点最大值称为B树的阶,通常用m表示。一个结点有k个孩子时,必有k-1个关键字才能将子树中所有关键字划分为k个子集。
1.根结点至少有两个子女。
2.每个中间节点都包含k-1个元素和k个孩子。
3.每一个叶子节点都包含k-1个元素。
4.所有的叶子结点都位于同一层。
5.每个节点中的元素从小到大排列,节点当中k-1个元素正好是k个孩子包含的元素的值域划分
2.2查询示例
以上图为例:若查询的数值为5:
第一次磁盘IO:在内存中定位(与17、35比较),比17小,左子树;
第二次磁盘IO:在内存中定位(与8、12比较),比8小,左子树;
第三次磁盘IO:在内存中定位(与3、5比较),找到5,终止。
三、b+树
3.1简介
一个m阶的B+树具有如下几个特征:
1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。
2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。
3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。
4.B+树通常有两个指针,一个指向根结点,另一个指向关键字最小的叶子结点。因些,对于B+树进行查找两种运算:一种是从最小关键字起顺序查找,另一种是从根结点开始,进行随机查找。
下面是一棵3阶的B+树:
四、b+树与b树的比较
- b+树的中间节点不保存数据,B树的中间结点保存数据,所以对于数据量很大的情况下对内存的消耗很大,相比之下B+树很节省内存
- b+树查询必须查找到叶子节点,b树只要匹配到即可不用管元素位置,因此b+树查找更稳定(并不慢);
- 对于范围查找来说,B树的范围查找需要不断依赖中序遍历。首先二分查找到范围下限,再不断通过中序遍历,知道查找到范围的上限即可。整个过程比较耗时。 而B+树的范围查找则简单了许多。首先通过二分查找,找到范围下限,然后同过叶子结点的链表顺序遍历,直至找到上限即可。
- B树不允许关键字重复,B+树允许重复
- B+树中有k个子树的中间节点包含有k个元素(B树中是k-1个元素)
五、总结
查找数据,最简单的方式是顺序查找。但是对于几十万上百万,甚至上亿的数据库查询就很慢了。
所以要对查找的方式进行优化,熟悉的二分查找,二叉树可以把速度提升到O(log(n,2)),查询的瓶颈在于树的深度,最坏的情况要查找到二叉树的最深层,由于,每查找深一层,就要访问更深一层的索引文件。在多达数G的索引文件中,这将是很大的开销。所以,尽量把数据结构设计的更为‘矮胖’一点就可以减少访问的层数。
在众多的解决方案中,B-/B+树很好的适合。B-树定义具体可以查阅,简而言之就是中间节点可以包括两个子节点,而且中间的元素可以是一个域。相比B-树,B+树的父节点也必须存在于子节点中,是其中最大或者最小元素,B+树的节点只存储索引key值,具体信息的地址存在于叶子节点的地址中。这就使以页为单位的索引中可以存放更多的节点。减少更多的I/O支出。因此,B+树成为了数据库比较优秀的数据结构。
MySQL中MyIsAM和InnoDB都是采用的B+树结构。不同的是前者是非聚集索引,后者主键是聚集索引,所谓聚集索引是物理地址连续存放的索引,在取区间的时候,查找速度非常快,但同样的,插入的速度也会受到影响而降低。聚集索引的物理位置使用链表来进行存储。