数据结构与算法--Tree(二叉树、B±树、红黑树)

在MySQL中,索引的的实现方式中使用的最多的就是B+Tree,那么为什么要选择B+Tree呢?我们就需要从最基本的二叉查找树说起

什么是二叉树?

二叉树 = (空树) | (节点+左右子二叉树)
解释:二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成。

各种二叉树

满二叉树

定义:除了叶结点外每一个结点都有左右子节点叶子结点都处在最底层的二叉树,也就是说一棵深度为k,且有2^k-1个节点的树是满二叉树
在这里插入图片描述

完全二叉树

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数第h 层所有的结点都连续集中在最左边,这就是完全二叉树。
满二叉树一定是完全二叉树,但完全二叉树不一定是满二叉树
在这里插入图片描述

二叉查找树( Binary Search Tree)

又称二叉排序树,那什么是二叉查找树呢,总结来说就是符合如下规则的的就是二叉查找树

  1. 某节点的左子树节点值仅包含小于该节点的值
  2. 某节点的右子树节点值仅包含大于该节点的值
  3. 左右子树每个也必须是二叉查找树

图示:
在这里插入图片描述
咦,这不是挺平衡的吗,左右对称。没错,这个刚好对称,按照这个逻辑也有不对称的,比如下面这个图
在这里插入图片描述
同样符合规则,但及其不平衡,查找次数或时间复杂度 O(h)可能会随着单边树长无限增长。
接下来我们使用动图看下二叉查找树的排序过程:
在这里插入图片描述

平衡二叉查找树(AVL tree)

平衡二叉树是带有平衡条件的二叉树,当每个节点的左右子树高度差为最多为1,否则需要进行旋转达到树的平衡

当对一颗AVL树进行插入操作,可能会导致AVL树不平衡,此时,我们就需要做平衡处理,假设重新平衡的节点为N,则不平衡会下列四种情况:

  • 在N的左孩子的左子树插入(LL)
    在这里插入图片描述
    由于在E的左孩子C的左子树B上插入节点A,使E的左右子树高度差变为2(>1)导致树失去平衡。所以需要进行一次旋转操作:
  1. 将E的左孩子C向右上旋转为根节点
  2. E向右下旋成为C的右子树
  3. 原来C的左子树D变为E的左子树
  • 在N的右孩子的右子树插入 (RR)
    在这里插入图片描述
    在节点E的右子树插入F后,使得A的平衡因子由-1减至-2而失去平衡,需要做一次逆时针旋转操作:
  1. 将A的右孩子C向左上旋转代替A作为根节点
  2. A向左下旋转变为C的左子树
  3. 原来C的左子树变为A的右子树
  • 在N的左孩子的右子树插入(LR)
    在这里插入图片描述
    这里LL或RR不同的是需要进行两次旋转操作(先逆时针后再顺时针),首先将LR调整为LL,然后对LL进行调整为平衡,过程如下:
  1. 第一次旋转:调增为LL
    • 将A节点的左孩子B的右子树D向左上旋转到B节点位置
    • B节点向下旋转为D的左子树
  2. 第二次旋转:平衡LL
    • 将D右上旋转,代替根节点A的位置
    • 原有的根节点A向下旋转为D的有孩子
    • F为A的左孩子
  • 在N的右孩子的左子树插入 (RL)
    在这里插入图片描述
    与LR类似,需要做两次的旋转操作(先顺时针旋转后再逆时针旋转),首先将RL调整为RR,然后再根据RR进行平衡,过程如下:
  1. 第一次旋转:调整为RR
    • 将根节点A的右孩子D向左上旋转代替C的位置
    • 原有的C变为D的右孩子
  2. 第二次旋转:平衡RR
    • 将D向左上旋转,代替原本A根节点位置
    • 原本A变为D的左孩子根节点
    • F调整为A的右子树

红黑树(Red-Black Tree)

为什么要有红黑树?

解决二叉查找树的不平衡问题。

什么是红黑树?

红黑树是一种二叉的查找树,二叉查找树的性能却决于它的高度,而红黑树其实就是一种树的平衡策略,红黑树上的每一个节点都遵循如下规则:

  1. 每个节点都有红色或黑色
  2. 树的根始终黑色的
  3. 没有两个相邻的红色节点(相邻指的是父节点或子节点相邻。其中黑色在某些情况下可以连续)
  4. 从根节点或其它节点出发到任何后代NULL(就是叶子节点之后的节点)节点的每条路径都具有相同数量的黑色节点

这里有两个概念需要弄清楚

  • recolor(根据规则重新标记颜色)
    假设着是一个二叉树,然后插入节点值4的节点,根据规则,会触发recolor
    在这里插入图片描述
    插入后发现违反了第三条规则,需要重新调整颜色
    在这里插入图片描述

这里做了两个调整:

  1. 将0007调整为黑色,左侧符合要求
  2. 但右侧从根节点触发没有黑色节点,违反第四条规则,然后把0015也置为黑色后就完全满足红黑树规则了

在这里插入图片描述

  • rotation(旋转,主要是这个进行平衡)
    首先我们先放置两个节点如下图:
    在这里插入图片描述
    当再插入一个节点0005的时候,二叉树就不平衡了
    在这里插入图片描述
    就会触发rotation进行旋转(可以想象把0007节点提起来),然后重新根据recolor调整颜色,最终符合规则
    在这里插入图片描述
    在这里插入图片描述
    接下来我我们通过动图看下如何把二叉查找树的不平衡状态调整为平衡状态,这里我们依次插入10、9、8、7节点值的节点
    在这里插入图片描述
    总结来说,步骤如下:
  1. 节点在符合二叉排序树的规则插入(删除)后
  2. 判断二叉树是否平衡,如果不平衡则进行rotaion旋转,就是把中间的节点像线一样提起来
  3. 然后判断红黑颜色是否符合规则,不符合再进行recolor(重新调整颜色)

B系列树

B-Tree(B-树)

定位索引,数据与索引存储在一个节点中,无需再定位数据

  • 为什么要使用B-Tree?
    红黑树也可以实现B-Tree同样的功能来实现索引,但在MySQL中,索引是存在磁盘上的,对磁盘进行I/O要比对内存进行存取高出好几个数量级,因此使用B-Tree主要目的是减少查找过程中磁盘I/O的存取次数

  • B-Tree规则:

  1. 所有键值分布在整颗树中
  2. 任何一个关键字只会出现在一个节点中(没有冗余)
  3. 搜索有可能在非叶子节点结束(因为key/value都是在一个节点中)
  4. 通过关键字在全树中做一次查找,性能与二分查找相近

在这里插入图片描述

B+Tree(B+树)

先定位索引再通过索引高效快速定位数据

  • 为什么使用B+Tree?
  1. B+Tree主要是为了比B-Tree更少的磁盘I/O次数,通过非叶子节点不存储value,让一个节点可以存储更多的key,所以同样一次磁盘I/O操作,B+Tree能够读取更多的索引信息,I/O的效率就更高了

    这里的I/O是高多少,我们可以来计算下:
    在MySQL中InnoDB存储引擎中页默认大小为16KB,假设表的主键类型为bigint(8字节),指针类型也为8字节,也就是一个页(也就是B+Tree的一个节点)可以存储16KB/(8B+8B)=1000个key,如果树的高度为3(就是深度为3)的B+Tree可以维护100010001000=10亿条记录
    如果在B-Tree中,假设data大小为512字节,那么一个节点存储16KB/(8+8+512)=30,深度为3的话B-Tree可以维护303030=27000条记录,着差距显而易见!

  2. MySQL是一种关系型数据库,区间访问是常见的一种情况,将每个叶子节点相连,可使用范围区间对叶子节点进行查询(B-Tree非叶子节点也有存数据,无法范围区间查询)

  • 与B-Tree的区别
  1. 所有非叶子节点仅存储key,不存储value(只有叶子节点才存储真正的数据)
  2. 为所有叶子节点之间增加一个链指针
  3. 一个关键字key必定会在叶子节点出现(带value),也有可能在非叶子节点出现(不带value)
  • 与红黑树用途区别
  1. 红黑树更多用于内部排序,需要排序的数据都在内存中,比如Map、Set就有用到红黑树
  2. B+树主要是为文件存储而生(比如索引文件是放在磁盘中),一个节点一般对应一个block,避免树形结构不断向下查找,然后磁盘不停寻道、读数据,减少了I/O次数。
  3. B+数据只需要遍历叶子节点就可以实现整棵树遍历,而其它树形结构需要中序遍历(中左右)才能访问所有数据

在这里插入图片描述

扩展

局部性原理

为了提高I/O效率,磁盘中默认有预读处理,比如读取一个字节,磁盘会顺序向后读取一定长度(一般为页的倍数,通常为4k)的数据放入内存
MySQL就是利用了磁盘预读原理,将B+Tree节点大小设计为一个页的大小,保证一个节点对应一个物理上的一个页,加上计算机存储分配都是按页对其,所以每个节点仅需一次I/O操作。包括叶子节点使用链指针连接也是为了符合局部性原理,提高查找效率

四叉树

应用:主要表达二维空间
定义:它的每个节点下至多可以有四个子节点,通常把一部分二维空间细分为四个象限或区域并把该区域里的相关信息存入到四叉树节点中。
在这里插入图片描述
四个大正方形可以分为四个小正方形,小正方形又可以分为四个更小的正方形

八叉树

应用:主要表达三维空间
定义:若不为空树的话,树中任一节点的子节点恰好只会有八个或零个,也就是子节点不会有0与8以外的数目
在这里插入图片描述
一个三维图形可以分为8个小正方体,小正方体又可以分为8个更小的正方体。

总结

从二叉排序树到B+Tree,发现每一种树的发展都是由历史原因的,到了B+Tree中,磁盘I/O存取次数最少、深度最浅、单节点保存数据最多,只需要将ROOT节点存储在内存中,就可以很快的在10亿条数据中查找记录。

参考资料

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我思知我在

原创不易,多多一键三连

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值