树表的查找——二叉排序树->AVL平衡二叉树->红黑树->B树->B+树

文章探讨了从二叉排序树到B+树的演变过程,强调了平衡树的重要性,如AVL树和红黑树。B树和B+树的设计是为了优化磁盘I/O,减少查找操作的深度,提高数据库等场景的性能。B+树因其在范围查询和存储效率上的优势,在数据库索引中广泛应用。
摘要由CSDN通过智能技术生成

前沿

这篇博客是一篇总结性文章。更适合你已经在B站等地方系统学习过了几种树的数据结构是什么样的,脑海里有清晰的结构了,再来看!

关于树表的查找是有一个演进的思路的,也就是“二叉排序树-平衡二叉树-红黑出-B树-B+树”,所以我们不仅要关注每一种树的特点是什么,还要关注每一种树的缺点是什么,这样才能明白为什么最终演进到了B+树(当然其他树也不是不能用哈,比如插入操作少查询操作多的时候用AVL也没毛病,HashMap用的红黑树也没毛病)。

不想看文字就来看这个视频:终于把B树搞明白了(一)_B树的引入,为什么会有B树_哔哩哔哩_bilibili

零、二叉排序树

二叉树的时间复杂度为0(logn)

缺点:如果是按照从小到大的顺序插入的,那么就会变成下面这样,又退化成了顺序查找,所以有了平衡二叉树

一、AVL平衡二叉树

AVL:左右两个子树的高度差的绝对值不超过1。和二叉排序树的区别在于,二叉排序树不要求两个子树的高度差小于等于1.

如何构造平衡二叉树呢:分为两种情况,在算法题中,直接给定了一个数组,那么首先将数组排序,然后以二分法的方式访问先序建立二叉树就得到了一个平衡二叉树,但是我们发现如果删除了一个节点可能就失衡了,所以我说这是leetcode算法题中才这样去做。然而在现实情况中,是采用旋转的方式:插入一个值或者删除一个值导致二叉树失衡,就用旋转的方式弄到平衡!

缺点

1)因为二叉树的结点只能分两个叉,所以当结点个数多时,二叉树的高度难免过于深。访问一个结点就要进行一次磁盘的I/O,所以二叉树作为存储结构可能导致I/O次数太多(同时这也是红黑树的缺点)。

2)插入和删除可能破坏二叉树的平衡。插入一个结点和删除一个结点都要进行二叉树的旋转,这是非常耗时的,所以有了红黑树

二、红黑树

        红黑树首先是一个二叉排序树。

        平衡二叉树大量的旋转操作是因为它对自己要求太高了,左右两颗子树的高度差不能超过1,那么我们就适当降低要求:让高子树不超过矮子树的两倍即可,这样就能减少旋转的次数。红黑树同时引入了颜色(颜色如何发挥作用的不想管了),当插入或删除数据时,只需要进行O(1)次数的旋转以及变色就能保证基本的平衡,不需要像AVL树进行O(lgn)次数的旋转。

缺点:红黑树只改善了AVL旋转耗时的问题,但是红黑树也是二叉的,也会导致I/O次数过多。

但是对于HashMap和TreeMap这种内存中的对象,我们不需要做磁盘上的I/O,那么红黑树足够了

三、B树:为磁盘而生

其实还存了主键,看下图:

是为磁盘等辅存设备设计的多路平衡查找树,AVL和红黑树太高太瘦了,而B树是一颗“矮胖子”,磁盘IO次数大大减少。

定义B树最重要的概念是阶数(Order),对于一颗m阶B树,需要满足以下条件:

  • 每个节点最多包含 m 个子节点。
  • 如果根节点包含子节点,则至少包含 2 个子节点;除根节点外,每个非叶节点至少包含 m/2 个子节点。
  • 拥有 k 个子节点的非叶节点将包含 k - 1 条记录。
  • 所有叶节点都在同一层中(农行笔试考过哦~)。

可以看出,B树的定义,主要是对非叶结点的子节点数量和记录数量的限制。

缺点

(1)B树要求一个page(一个树种的节点)是16K,我们假设一条记录占1K大小,那么三层的B数最多存储4096条数据(实际上少于,因为指针也占空间),那么如果数据库里有1w条呢?再加一层,20w条呢?再加一层,由退回到之前那个I/O次数过多的问题了。那我们想一下,为什么3层只能存4096这么少的数据量呢?因为每个非叶子节点不仅存了主键和指针还存储了数据本身,数据本身占的空间太多了,导致分叉太少了,也就导致树不够矮胖,所以有了B+树。

(2)还有一个缺点,因为B树的相邻节点之间没有指针相连,所以当发生范围查询的时候,和哈希表一样,都要一个一个找

B树在数据库中也有一些应用,如mongodb的索引使用了B树结构。但是在很多数据库应用中,使用了是B树的变种B+树。 

 四、B+树

B+树也是多路平衡查找树,其与B树的区别主要在于:

  • B树中每个节点(包括叶节点和非叶节点)都存储真实的数据,B+树中只有叶子节点存储真实的数据,非叶节点只存主键。在MySQL中,这里所说的真实数据,可能是行的全部数据(如Innodb的聚簇索引),也可能只是行的主键(如Innodb的辅助索引),或者是行所在的地址(如MyIsam的非聚簇索引)。
  • B树中一条记录只会出现一次,不会重复出现,而B+树的键则可能重复重现——一定会在叶节点出现,也可能在非叶节点重复出现。
  • B+树的叶节点之间通过双向链表链接。
  • B树中的非叶节点,记录数比子节点个数少1;而B+树中记录数与子节点个数相同。

由此,B+树与B树相比,有以下优势:

  • 更少的IO次数:B+树的非叶节点只包含键,而不包含真实数据,因此每个节点存储的记录个数比B数多很多(即阶m更大),因此B+树的高度更低,访问时所需要的IO次数更少。此外,由于每个节点存储的记录数更多,所以对访问局部性原理的利用更好,缓存命中率更高。
  • 更适于范围查询:在B树中进行范围查询时,首先找到要查找的下限,然后对B树进行中序遍历,直到找到查找的上限;而B+树的范围查询,只需要对链表进行遍历即可。
  • 更稳定的查询效率:B树的查询时间复杂度在1到树高之间(分别对应记录在根节点和叶节点),而B+树的查询复杂度则稳定为树高,因为所有数据都在叶节点。

B+树也存在劣势:由于键会重复出现,因此会占用更多的空间。但是与带来的性能优势相比,空间劣势往往可以接受,因此B+树的在数据库中的使用比B树更加广泛。

六、B+树的魅力

前面说到,B树/B+树与红黑树等二叉树相比,最大的优势在于树高更小。实际上,对于Innodb的B+索引来说,树的高度一般在2-4层。下面来进行一些具体的估算。

树的高度是由阶数决定的,阶数越大树越矮;而阶数的大小又取决于每个节点可以存储多少条记录。Innodb中每个节点使用一个页(page),页的大小为16KB,其中元数据只占大约128字节左右(包括文件管理头信息、页面头信息等等),大多数空间都用来存储数据。

  • 对于非叶节点,记录只包含索引的键和指向下一层节点的指针。假设每个非叶节点页面存储1000条记录,则每条记录大约占用16字节;当索引是整型或较短的字符串时,这个假设是合理的。延伸一下,我们经常听到建议说索引列长度不应过大,原因就在这里:索引列太长,每个节点包含的记录数太少,会导致树太高,索引的效果会大打折扣,而且索引还会浪费更多的空间。
  • 对于叶节点,记录包含了索引的键和值(值可能是行的主键、一行完整数据等,具体见前文),数据量更大。这里假设每个叶节点页面存储100条记录(实际上,当索引为聚簇索引时,这个数字可能不足100;当索引为辅助索引时,这个数字可能远大于100;可以根据实际情况进行估算)。

对于一颗3层B+树,第一层(根节点)有1个页面,可以存储1000条记录;第二层有1000个页面,可以存储1000*1000条记录;第三层(叶节点)有1000*1000个页面,每个页面可以存储100条记录,因此可以存储1000*1000*100条记录,即1亿条。而对于二叉树,存储1亿条记录则需要26层左右。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值