数据结构中常见的树 BST AVL RBT B- B+ B*

内容会持续更新,有错误的地方欢迎指正,谢谢!

二叉搜索树BST

又名二叉查找树、二叉排序树、B树。

BST需满足如下要求:

1.所有非叶子结点至多拥有两个儿子(Left和Right);
2.所有结点存储一个关键字,且关键字互不相等;
3.根节点的值大于左子树所有节点的值,并小于右子树所有节点的值;(注意是 所有!)
4.左右子树仍然为BST;

这里写图片描述

另外,因为一棵由n个结点随机构造的二叉查找树的高度为lgn,所以顺理成章,二叉查找树的一般操作的执行时间为O(lgn)。但是二叉搜索树有个大问题:如果插入的n个数据是随机的,则执行效果会很好;但如果插入的n个数据是有序的或逆序的,那么二叉搜索树的执行速度就变得很慢。因为当插入数值有序时,二叉查找树便退化成了一棵具有n个结点的线性链。导致它查找、插入和删除数据的执行时间变成了O(n),如图:

这里写图片描述

所以,有了下方的AVL和BST来保证树总是平衡的(或者至少大部分是平衡的)。

严格平衡二叉搜索树AVL

AVL需满足如下要求:
1.左右子树深度之差的绝对值不大于1;
2.左子树和右子树仍然为AVL。

AVL的插入、删除,再重建平衡

插入和删除都和普通二叉树一样,只是多了保持平衡的一步(通过旋转保持AVL树的平衡)
旋转分为左旋和右旋,这两种操作是对称的。
这里写图片描述

AVL树操作的时间复杂度:

  1. 插入操作需要O(lg n)的遍历时间以及至多两次旋转的常数时间;
  2. 删除操作需要O(lg n)的遍历时间以及若干次旋转的常数时间;

总的来说,AVL树的插入和删除都只需要O(lg(n))的时间。

红黑树(非严格平衡二叉搜索树)RBT

RBT的概念

RBT的每个结点都含五个域:color、key、left、right、p。其本质上是一棵二叉查找树,但它在二叉查找树的基础上增加了着色和着色相关的性质使得红黑树相对平衡,从而保证了红黑树的查找、插入、删除的时间复杂度最坏为O(log n)。

AVL和RBT的比较

AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比RBT要多;RBT是弱平衡的,用非严格的平衡来换取 (增删节点的时候) 旋转次数的降低。
所以,若搜索的次数远远大于插入和删除,就选择AVL树;若搜索、插入、删除次数几乎差不多,就选择RBT。

RBT的两个特征:

1.节点都有颜色;2.在插入和删除的过程中,颜色要遵循一些的规则。第一个特征用个bool值来记录节点的颜色就解决了,主要是第二个特征需要满足红-黑规则:

  1. 每个结点要么是红的,要么是黑的;
  2. 根结点是黑的;
  3. 如果一个结点是红的,那么它的俩个儿子都是黑的(反之不一定);
  4. 每个叶结点(这个叶结点指树尾端NIL指针或NULL结点)都是黑的。
  5. 从根节点到叶结点的每条路,黑色结点数相同(即相同的黑色高度);

补充: 根据第5条规则,可得出:从根结点到叶节点的最长长度 顶多等于 从根节点到叶节点的最短长度的两倍。

正是红黑树的这5条性质,使一棵n个结点的RBT保持了log(n)的高度和最坏为O(log n)的时间复杂度。

上面所说的树尾端NIL指针或NULL节点如下方所示:
这里写图片描述

在RBT中插入的节点应为红色的,因为插入一个红色节点比插入一个黑色节点违背红-黑规则的可能性更小。具体原因:插入黑色节点总会改变黑色高度,违背规则5;但插入红色节点有可能会违背规则3。另外违背规则3比违背规则5要更容易修正。当插入一个新的红色节点时,有可能会破坏这种平衡性,那么RBT是如何修正的呢?

平衡性的修正

对RBT进行插入或删除操作,可能会破坏其的平衡,可通过三种方式对平衡进行修正:
1. 改变节点颜色
2. 左旋
3. 右旋

左旋

左旋操作:解决向右倾斜问题。

这里写图片描述

这里写图片描述

右旋

右旋与左旋刚好相反。

这里写图片描述

这里写图片描述

树在经过旋转后,树的红黑性质被破坏了,所以,在RBT中插入和删除数据后,需要利用旋转与颜色重涂来重新恢复树的红黑性质。

补充: 双旋只是单旋的两次应用而已。

插入和删除操作

插入

由于RBT是二叉搜索树的改进版,也自然有二叉搜索树的性质,新插入的节点都在最下方那一层,也就是其在插入后都成为了叶节点。

另外,RBT和二叉搜索树的插入操作的插入过程是相同的:先找到待插入的位置,再将节点插入。
插入操作的步骤:
1. 找到要插入的点的根节点
2. 判断该点是插在根节点的左子节点还是右子节点
3. 将它重新修整为一颗RBT(即:何时变色,何时左旋,何时右旋)

RBT和二叉搜索树的插入操作的不同处在于:RBT在插入后会重新修整,即第3步:

情况1:插入节点的父节点和其叔叔节点(祖父节点的另一个子节点)均为红色的。此时,肯定存在祖父节点,但是不知道父节点是其左子节点还是右子节点,但是由于对称性,我们只要讨论出一边的情况,另一种情况自然也与之对应。这里考虑父节点是祖父节点的左子节点的情况,如下图所示:
这里写图片描述
对于这种情况,我们要做的操作有:将当前节点(4)的父节点(5)和叔叔节点(8)涂黑,将祖父节点(7)涂红,变成下图所示的情况。再将当前节点指向其祖父节点,再次从新的当前节点(7)开始。这样上右图就变成了情况2了。
这里写图片描述

情况2: 插入节点的父节点是红色,叔叔节点是黑色,且插入节点是其父节点的右子节点。我们要做的操作有:将当前节点(7)的父节点(2)作为新的节点,以新的当前节点为支点做左旋操作。完成后如下图所示,这样左下图就变成情况3了。
这里写图片描述
情况3: 插入节点的父节点是红色,叔叔节点是黑色,且插入节点是其父节点的左子节点。我们要做的操作有:将当前节点的父节点(7)涂黑,将祖父节点(11)涂红,在祖父节点为支点做右旋操作。最后把根节点涂黑,整个红-黑树重新恢复了平衡,如右上图所示。至此,插入操作完成!
这里写图片描述

总结: 如果是从情况1开始发生的,必然会走完情况2和3,也就是说这是一整个流程。当然,实际中可能不一定会从情况1发生,如果从情况2开始发生,那再走个情况3即可完成调整。如果从情况3开始发生,则只要调整情况3,那么前两种情况均不需要调整了。故变色和旋转之间的先后关系可以表示为:变色->左旋->变色并右旋。

删除

红-黑树的删除和二叉查找树的删除是一样的,只不过删除后多了个平衡的修复而已。

有三种情况:
1. 如果待删除节点没有子节点,那么直接删掉即可;
2. 如果待删除节点只有一个子节点,那么直接删掉,并用其子节点去顶替它;
3. 如果待删除节点有两个子节点,这种情况比较复杂:首选找出它的后继节点,然后处理“后继节点”和“被删除节点的父节点”之间的关系,最后处理“后继节点的子节点”和“被删除节点的子节点”之间的关系。

第3种情况,又可分为多种情况以处理平衡,也就是使其满足红-黑规则。个人认为删除类似于插入,所以,了解插入的过程即可,挺复杂的,这里省略。

B-树

B-树是一种多路搜索树,并不是二叉的。

B-树规则
  1. 定义任意非叶子结点最多只有M个儿子;且M>2;
  2. 根结点的儿子数为[2, M];
  3. 除根结点以外的非叶子结点的儿子数为[M/2, M];
  4. 每个结点存放至少M/2-1(取上整)和至多M-1个关键字(至少2个关键字);
  5. 非叶子结点的关键字个数=指向儿子的指针个数-1;
  6. 非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
  7. 非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树,P[M]指向关键字大于K[M-1]的子树;
  8. 所有叶子结点位于同一层。

如:(M=3)

这里写图片描述

B-树的搜索

从根结点开始,对结点内的关键字(有序)序列进行二分查找,如果命中则结束,否则进入查询关键字所属范围的儿子结点;重复,直到所对应的儿子指针为空或已经是叶子结点。

B-树的特性
  1. 关键字集合分布在整颗树中;
  2. 任何一个关键字出现且只出现在一个结点中;
  3. 搜索有可能在非叶子结点结束;
  4. 搜索性能等价于在关键字全集内做一次二分查找,即搜索性能与M值无关;
  5. B-树的分裂和合并:由于M/2的限制,在插入结点时,如果结点已满,需要将结点分裂为两个各占M/2的结点;删除结点时,需将两个不足M/2的兄弟结点合并。

B+树

B+树是B-树的变体,也是一种多路搜索树:

B+树规则

其定义基本与B-树相同,除了以下四点:

  1. 非叶子结点的子树指针与关键字个数相同;
  2. 非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间);
  3. 为所有叶子结点增加了一个链指针;
  4. 所有关键字都在叶子结点出现。

如:(M=3),DATA为输入数据,Q表示两个链表之间可传输数据。

这里写图片描述

B+树的搜索

B+的搜索与B-树也基本相同,区别是B+树只有达到叶子结点才命中(B-树可以在非叶子结点命中),其性能也等价于在关键字全集做一次二分查找。

B+树的特性
  1. 所有关键字都出现在叶子结点的链表(稠密索引),且链表中的关键字恰好是有序的;
  2. 不可能在非叶子结点命中;
  3. 非叶子结点是叶子结点的索引(稀疏索引),叶子结点相当于是存储关键字的数据层;
  4. 常用于文件索引系统和数据库;
  5. B+树的分裂和合并:当一个结点满时,分配一个新的结点,并将原结点中1/2的数据复制到新结点,最后在父结点中增加新结点的指针;B+树的分裂只影响原结点和父结点,而不会影响兄弟结点;删除结点时,需将两个不足M/2的兄弟结点合并。

B*树

是B+树的变体,在B+树的非根和非叶子结点再增加了指向兄弟的指针

这里写图片描述

B*树定义了非叶子结点关键字个数至少为(2/3)*M,即最低使用率为2/3(代替B+树的1/2);

B*树的分裂:当一个结点满时,如果它的下一个兄弟结点未满,那么将一部分数据移到兄弟结点中,再在原结点插入关键字,再修改父结点中兄弟结点的关键字(因为兄弟结点的关键字范围改变了);如果兄弟也满了,则在原结点与兄弟结点之间增加新结点,并各复制1/3的数据到新结点,最后在父结点增加新结点的指针。

所以,B*树分配新结点的概率比B+树要低,因而空间使用率更高。

参考

【1】数据结构中常见的树
http://blog.csdn.net/sup_heaven/article/details/39313731
【2】【数据结构和算法05】 红-黑树
http://blog.csdn.net/eson_15/article/details/51144079
【3】 教你初步了解红黑树
http://blog.csdn.net/v_JULY_v/article/details/6105630
【4】B树,B-树和B+树的区别
http://blog.csdn.net/zwz2011303359/article/details/63262541###

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值