二叉树

二叉树的特点是,左子树的键值小于根的键值,右子树的键值大于根的键值

但是二叉树在某些场景下,会是这样的结构

这种结构的二叉树是非平衡的,层级过高,甚至已经退化成链表,会导致查询效率过低

平衡二叉树(AVL)

在二叉树的基础上,衍生出了平衡的二叉树,平衡二叉树的规则是,任何节点的两个子树的高度差<=1

以上述二叉树为例,在插入1\~5的时候,过程如下

可以看见每次子树的高度差在大于1的时候,平衡二叉树都会进行旋转,让结构保持平衡

根据失衡前的状态,可以分为4种状态
LL:插入或删除一个节点后,发现根节点的节点的节点下还有非空节点,导致根节点的节点的高度比根节点的节点的高度大2,平衡树失衡,需要进行旋转来保持平衡,示意图如下

LR:插入或删除一个节点后,发现根节点的节点的节点下还有非空节点,导致根节点的节点的高度比根节点的节点的高度大2,平衡树失衡,需要进行旋转来保持平衡,示意图如下

RR:插入或删除一个节点后,发现根节点的节点的节点下还有非空节点,导致根节点的节点的高度比根节点的节点的高度大2,平衡树失衡,需要进行旋转来保持平衡,示意图如下

RL:插入或删除一个节点后,发现根节点的节点的节点下还有非空节点,导致根节点的节点的高度比根节点的节点的高度大2,平衡树失衡,需要进行旋转来保持平衡,示意图如下

平衡二叉树追求绝对平衡,每次插入或删除新节点之后需要旋转的次数不能预知,如果相关的插入和删除操作并不频繁,而是查找操作相对更频繁,那么就优先选择平衡二叉树树进行实现

红黑树

红黑树也是一种平衡的二叉树,不过相比于AVL树,红黑树的平衡没有那么绝对,红黑树需要不断的去变色或者旋转来满足以下规则:

  • 节点是红色或黑色。
  • 根是黑色。
  • 所有叶子都是黑色(叶子是NIL节点)。
  • 每个红色节点必须有两个黑色的子节点。(从每个叶子到根的所有路径上不能有两个连续的红色节点。)
  • 从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点(简称黑高)。

Hash表

说到hash表,很多人会想到hashmap,hash表是一种基于散列,在关键字key和值value之间建立映射关系f的数据结构,这种映射关系f我们称为哈希函数,通过计算并存储value的这块连续存储空间称为哈希表,通过计算的key得到的存储地址称为哈希地址

注意,hash值和java中的hashcode()方法得到的值不是同一种事物!hash值是经过hash算法计算得到的输出值,而hashcode是java根据对象地址等计算出的int类型的值

1.哈希函数

哈希函数有多种计算方法

  • 直接定址法:将key的某个线性函数值作为哈希地址
  • 数字分析法:选取key中的一部分作为运算参数计算哈希地址
  • 平方取中法 :对key进行平方计算,取中间段作为哈希地址
  • 折叠法:将key分成长度相同的几段,计算叠加和,再选取后几位作为哈希地址
  • 除留余数法 :对key直接取模(求余数),将值作为哈希地址
  • 随机数法:取key的随机函数值作为哈希地址
2.哈希碰撞(哈希冲突)

在进行哈希函数计算之后,得到的hash值依然有相等的可能,这种现象称作哈希碰撞,智慧的先驱者们又想出了几种方案来解决这种冲突问题。

3.哈希碰撞解决方案
  • 开放地址法:发生冲突就去探测寻找下一个空的地址,开放地址法有可能会发生多个不同key探测到同一个空的地址并进行竞争的现象,称为堆积
  • 再哈希:发生冲突后,采用另一个哈希函数进行哈希运算,直到得到一个唯一的哈希地址
  • 链表地址法:对于每个哈希地址,都维护一个单向链表进行value的存储,链表的每个节点都存储下一个节点的指针地址,hashmap就是用的这种数据结构
  • 公共溢出区法:维护两张表,基本表和溢出表,将未发生冲突的数据放入基本表,将发生冲突的数据放入溢出表,查询时先在基本表中查找到对应哈希地址的位置并比较(推测应该是在哈希地址相同的基础上进一步比较key),如果不相等再去溢出表中查找
    ps:对于溢出表中多个相同哈希地址的数据,我也查阅了很多资料,但是这块没有说的比较清晰的,个人猜测溢出表的结构也是以链表的形式进行存储的

B-tree

B-tree的结构如图所示,它的所有索引元素不重复,因此,B-tree的数据在每一阶都有相应的存储数据。另外,它的叶子节点没有指针,只单纯的存储数据。

举个例子,如果要查询索引值为12的数据,在第一阶可以看到12<17,所以由P1指针指向了磁盘页2(对于B-tree和B+tree来说,一个节点就是一个磁盘页),接着按顺序查找,找到了相同的索引值12,直接返回12存储的data值,如果没找到,依次类推,去下一阶进行查找。所以,在B-tree中,才设计成了不重复索引元素的结构。


(相关图例引用自https://blog.csdn.net/a764340703/article/details/82621781

B+tree

B+tree的结构如图所示,它和B-tree最大的区别在于:

  • B+tree的非叶子节点会有冗余索引
  • B+tree的所有数据全部存储在叶子节点上,这样操作好处在于同阶条件下,能存储更多的数据
  • B+tree的叶子节点有双向指针,对于范围查找的效率能大大提升

更多的B+tree结构在数据库中的应用我会在mysql章节介绍,敬请期待

推荐一个数据结构可视化网站,来自旧金山大学 David Galles
https://www.cs.usfca.edu/\~galles/visualization/Algorithms.html

03-05 15:22