参考:
微信
知乎
此三者的主要应用是降低大数据量检索时的时间复杂度。
- JAVA的hashMap中,当一个桶中的元素个数超过…时,桶内数据的存储结构会由链表改成红黑树。
- MySql数据库中,对于数据量超大的数据进行索引时,会采用B+树的存储结构。(索引数据结构的演变:红黑树->B树->B+树)
二叉查找树
对二叉树做中根遍历,数据是有序的,也称二叉排序树、二叉搜索树。
- 每个节点最多有两个子节点
- 节点的左子树中所有节点的值都小于这个节点的值,节点的右子树中所有节点的值都大于这个节点的值
平衡二叉树
每个节点的左右两个子树的高度差不大于1的二叉搜索树。
红黑树
红黑树是一种自平衡二叉查找树,又称为"对称二叉B树",它的统计性能要好于平衡二叉树。其典型的用途是实现关联数组。
特性
- 每个节点都带有颜色属性
- 根节点黑色、叶节点黑色、叶子节点必须是NULL
- 红色节点的两个子节点都是黑色
- 从任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点
自平衡
通过右旋、左旋、变色来实现。
- 左旋:假设以节点P为轴做左旋操作,那么其右子节点R变更为根节点,其自身变更为R的左子节点,R原来的左子节点变更为P的右子节点
- 右旋:对节点P做右旋操作,则P的左子节点L变更为根节点,P变更为L的右子树,L原来的右子树变更为P的左子树。
- 变色:节点变颜色
插入新的节点时,自平衡规则
首先,插入的节点的颜色初值设为红色。 - 无需调整的情况:当插入位置的父节点为黑色时
- 变色即可实现平衡:父节点和叔父节点(父节点的兄弟节点,不分左右)都为红色时,只需将插入的节点颜色变为黑色即可。空树插入时,插入的节点为根,只需将节点颜色变为黑色即可。
- 旋转+变色:都是在父红、叔父黑色情况下,
- 父节点为左子节点,插入节点为左子节点,即【左左】插入,需要祖父节点右旋+变色
- 父节点为左子节点,插入节点为右子节点,即【左右】插入,需要父节点左旋+祖父节点右旋+变色
- 父节点为右子节点,插入节点为左子节点,即【右左】插入,需要父节点右旋+祖父节点左旋+变色
- 父节点为右子节点,插入节点为右子节点,即【右右】插入,需要祖父节点左旋+变色
删除节点
- 待删除节点的左右子节点都为 null,删除时直接将该节点置为 null。
- 待删除节点的左右子节点有一个有值,则用有值的节点替换该节点即可。
- 待删除节点的左右子节点都不为 null,则找前驱或者后继,将前驱或者后继的值复制到该节点中,然后删除前驱或者后继
- 节点删除后可能会造成红黑树的不平衡,这时我们需通过【变色】+【旋转】的方式来调整,使之平衡。
B树
红黑树是二叉树,当数据量大时,其高度必然增大。且每次插入或者删除都需要做平衡操作,很是消耗时间。
B树,也是自平衡的排序查找树,但是不要求子节点数目必须小于2。
- 每个节点可以有最多M个子节点,M>=2,M即为B树的阶数
- 每个节点中可以存储最多M个、最少M/2向上取整个key,一般为2-3个。
- 所有叶子节点均在同一层
B树的构建
B树的构建过程中每个节点中的关键字的个数都在动态改变。
因为其构建过程是:对节点先扩充,当节点中关键字数量扩充到等于M时,再对其进行拆分,并将中间数升为父节点。
例如:定义一个5阶树(平衡5路查找树;),现在我们要把3、8、31、11、23、29、50、28 这些数字构建出一个5阶树出来;
遵循规则:
(1)节点拆分规则:当前是要组成一个5路查找树,那么此时m=5,关键字数必须<=5-1(这里关键字数>4就要进行节点拆分);
(2)排序规则:满足节点本身比左边节点大,比右边节点小的排序规则;
先插入 3、8、31、11
再插入23、29
再插入50、28
删除节点
规则:
(1)节点合并规则:当前是要组成一个5路查找树,那么此时m=5,关键字数必须大于等于ceil(5/2)(这里关键字数<2就要进行节点合并);
(2)满足节点本身比左边节点大,比右边节点小的排序规则;
(3)关键字数小于二时先从子节点取,子节点没有符合条件时就向向父节点取,取中间值往父节点放;
B+树
B+树是B树的升级优化版,
- 非叶子节点中的关键字不指向实际对象,也就是说B+树的非叶子节点不作存储作用,仅用作检索时的索引。
- 叶子节点保存了所有父节点的关键字指向的对象,所有数据地址必须到叶子节点才能获取到,因此所有数据的比较次数都一样
- 叶子节点中的所有关键字从小到大有序排列,每个节点的最后一个关键字记录了其右边的节点的第一个关键字的指针
- 非叶子节点的关键字数=子节点数