基础数据结构复习(B树,B+树,红黑树,LSM树)

527 阅读5分钟

2-3树

除了叶子节点每个节点有2个或3个孩子,存储1个或2个值

是B树的一个特例

2-3-4树

可以从2-3树类比推断得出

B树

2-3树(3阶B树),2-3-4树(4阶B树)都是B树的特例

B树是多路查找平衡树,高度一定是平衡的(叶子节点处于同一层),可以证明

B+树

特点:

  1. 只在叶子节点存储值,叶子节点内部的数据有序,叶子节点用双向链表连接,非叶子节点存储的是索引

  2. 非叶子节点存储的数据同时出现在叶子节点中,是叶子节点的最大值或最小值

B+树比B树的优势:

  1. 非叶子节点不存储卫星数据,一个磁盘页中能存下的索引页也就更多,相同数据量下,更加矮胖,所需要的磁盘IO次数更少(从根节点开始每向下访问一层需要一次磁盘IO)

  2. 相比于B树,查找一个特定的数据所需的时间更加稳定,因为都需要走到叶子节点那一层(叶子节点又处于同一层)才能找到key,而B树有可能在根节点就找到数据,也有可能需要遍历到叶子节点才找到数据,并不稳定

  3. 适合范围查找,B+树到叶子节点使用双向链表连接,数据天然有序,而B树需要中序遍历才能顺序访问数据

AVL树

自平衡二叉查找树:本身是一颗二叉查找树,需要复杂的操作来保持高度平衡(对任意节点,其左子树的高度和右子树的高度绝对值最多相差1)

平衡因子:左子树高度 - 右子树高度

最小失衡子树:平衡因子绝对值大于1(保证了失衡) && 子树中没有失衡子树的树(保证了最小)

失衡调整主要是通过旋转最小失衡子树来实现的,有左旋和右旋两种处理方式

插入

插入操作后只需要对插入栈中的弹出的第一个非平衡节点进行修正

  1. LL:新插入节点为最小不平衡子树根节点的左儿子的左子树上 → 右旋使其恢复平衡
  2. RR:类比上条规则
  3. LR:新插入节点为最小不平衡子树根节点左儿子的右子树上 → 左儿子为根左旋,原始根右旋
  4. RL:类比上条规则

删除

删除操作需要修正栈中的所有非平衡节点

  1. 叶子节点:直接删除,依次向上调整为AVL树(有可能造成递归删除操作)
  2. 只有左子树:该节点的值替换为左孩子的值,删除左孩子(因为删除之前是AVL树,没有右孩子只有左孩子,那左孩子必然没有子树)
  3. 只有右子树:类比上条规则
  4. 既有左子树又有右子树:该节点值替换为前驱节点的值,删除前驱节点(后继也行)(有可能造成递归删除操作)

总结:对于非叶子节点的删除,最终都将转化为对叶子节点的删除。

reference:blog.csdn.net/qq_21388535…

红黑树

  1. 非红即黑
  2. 根是黑
  3. 叶子( NIL,⚠️不是叶子节点)是黑
  4. 从任意一个节点,走到可达的叶子节点,走过相同的黑 -> 最长不会超过最短的2倍
  5. 不能出现连续红

理解:红黑树可以理解为2-3树的一种实现方式

优势:插入最多2次旋转达到平衡、删除最多3次旋转达到平衡

布隆过滤器

数据结构是bits数组

针对一个key,使用多个hash函数计算出多个位置(一个哈希函数生成一个位置),并把这些位置置为1

判读一个key是否存在?

计算这个key的各个哈希函数所对应的位置,如果其中有一个位置为0,则一定不存在,如果全部都为1,则该key可能存在

LSM树

没有固定的实现,是一种思想

思想的精髓:

  1. 先内存再磁盘
  2. 内存原地更新
  3. 磁盘追加更新
  4. 归并保留新值

一些约定:

  1. 横跨内存和磁盘的森林(很多树🌲组成)
  2. 只有level0存在于内存中,level1--leveln存在于磁盘中
  3. 内存中的level0子树采用有序的数据结构来保存数据(红黑树,跳表,avl树,treemap等)
  4. 磁盘中的level1--leveln子树本质上是排好序的文件
  5. 每一层子树都有固定的阈值,达到阈值后做merge操作
  6. 内存中的文件可以原地更新,磁盘中的内容是append only的

插入操作

只在内存中进行插入

删除操作

  1. 只在内存中存在:采用墓碑标记覆盖(为什么不直接删除?我猜测是因为不用进行树结构的调整)
  2. 只在磁盘中存在:插入墓碑标记
  3. 不存在:插入墓碑标记

修改操作

  1. 只在内存中存在:直接修改
  2. 只在磁盘中:直接插入
  3. 不存在:转换为插入操作,直接插入

查询操作

遍历level0到leveln到每一颗子树,直到找到目标值立刻返回不在寻找 因为最坏情况下要遍历所有的数据才能发现不存在目标值,所以查询的效率很低

  1. 只在内存中:遍历level0
  2. 只在磁盘中:遍历
  3. 在内存和磁盘中:意味着磁盘中的是老数据,所以遍历level0到leveln返回结果是完全正确的 可以使用稀疏索引 + 布隆过滤器来优化

合并操作

LSM树,long structure merged tree 原因:

  1. 内存不是无限大,所以需要把内存中的数据刷回磁盘中
  2. 磁盘上达到阈值的顺序文件进行合并,将合并结果写入下一层,归并过程是跟新数据和删除数据(通过墓碑标记)的过程

pros and cons

pros:利用来顺序磁盘IO,增删改效率极高 cons:读效率很低,不擅长范围的读操作,归并过程消耗次资源

特别鸣谢

zhuanlan.zhihu.com/p/415799237