【数据结构】

本文详细介绍了二叉搜索树中的AVL树和红黑树(RB树),以及B树和B+树的区别,重点讲述了它们的平衡策略、旋转操作和在实际应用中的优缺点。理解这些树结构有助于提升数据结构在搜索引擎、进程调度和文件系统中的性能优化。
摘要由CSDN通过智能技术生成

数据结构:

面试常考的几种树

1、BST(二叉排序树、二叉搜索树)

二叉搜索树或者是一颗空树,或者是具有下列性质的二叉树

  • 每个节点都有一个作为搜索依据的关键码key,所有节点的关键码互不相同;
  • 左子树(如果存在)上所有节点的关键码都小于根结点的关键码
  • 右子树(如果存在)上所有节点的关键码都大于根结点的关键码
  • 左子树和右子树也是二叉搜索树

总结:如果对一棵二叉搜索树进行中序遍历,可以按从小到大的顺序,将各节点关键码排列起来,所以也称二叉搜索树为二叉排序树

2、AVL树

一棵AVL树或者是空树,或者是具有下列性质的二叉搜索树:它的左子树和右子树都是AVL树,且左子树和右子树的高度之差的绝对值不超过1。

节点的平衡因子:

  • 每个节点附加一个数字,给出该节点右子树的高度减去左子树的高度所得的高度差。这个数字即为结点的平衡因子balance
  • 根据AVL树的定义,任一节点的平衡因子只能取-1,0,1
  • 如果一个节点的平衡因子的绝对值大于1,则这颗二叉搜索树就失去了平衡,不在是AVL树
  • 如果一颗二叉搜索树是高度平衡的,它就成为AVL树。如果它有n个节点,其高度可保持在O(log2n),平均搜索长度也可保持在O(log2n)

平衡化旋转:

  • 如果在一颗平衡的二插搜索树中插入一个新节点,造成了不平衡。此时必须调树的结构,使之平衡化;
  • (1)单旋转(左旋和右旋)(2)双旋转(左平衡和右平衡)
  • 在插入一个新节点后,需要从插入位置沿通向根的路径回溯,检查各节点的平衡因子(左右子树高度差);
  • 如果在某一节点发现高度不平衡,停止回溯
  • 从发生不平衡的节点起,沿刚才回溯的路径取直接下两层的节点
  • 如果这三个节点处于同一条直线上,则采用单旋转进行平衡化。
  • 如果这三个节点处于一个折线上,则采用双旋转进行平衡化。
左单旋
  • 如果在子树E中插入一个新结点,该子树高度增1导致结点A的平衡因子变成+2,出现不平衡。
  • 为使树恢复平衡,从A沿插入路径连续取3个结点A、C和E。它们处于一条方向为“”的直线上,需要做左单旋转。
  • 以结点C为旋转轴,让结点A反时针旋转。
右单旋
  • 在左子树D上插入新结点使其高度增1,导致结点A的平衡因子增到-2,造成了不平衡。
  • 为使树恢复平衡,从A沿插入路径连续取3个结点A、B和D,它们处于一条方向为“I”的直线上,需要做右单旋转。
  • 以结点B为旋转轴,将结点A顺时针旋转。
左双旋转
  • ·在子树F或G中插入新结点,该子树的高度增1。结点A的平衡因子变为-2,发生了不平衡。
  • 从结点A起沿插入路径选取3个结点A、B和E,它们位于一条形如"(”的折线上,因此需要进行先左后右的双旋转。
  • 首先以结点E为旋转轴,将结点B反时针旋转,以E代替原来B的位置,做左单旋转。
  • ·再以结点E为旋转轴,将结点A顺时针旋转,做右单旋转。使之平衡化。
右单旋转
  • 右左双旋转是左右双旋转的镜像。
  • 在子树F或G中插入新结点,该子树高度增1。结点A的平衡因子变为2,发生了不平衡。
  • 从结点A起沿插入路径选取3个结点A、C和D,它们位于一条形如")”的折线上,需要进行先右后左的双旋转。
  • 首先做右单旋转:以结点D为旋转轴,将结点C顺时针旋转,以D代替原来C的位置。
  • 再做左单旋转:以结点D为旋转轴,将结点A反时针旋转,恢复树的平衡。
特点:

1.有n个结点的AVL树的高度不招2/3log2(n+1)
2.在AVL树删除一个结点并做平衡化旋转所需时间为O(log2n)。
3.二叉搜索树适合于组织在内存中的较小的索引(或目录)。对于存放在外存中的较大的文件系统,用二叉搜索
树来组织索引不太合适。
4.在文件检索系统中大量使用的是用B_树或B+树做文件索引。

RB树

​ 红黑树(Red Black Tree)是- -种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。红黑树和AVL树类似,都是在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
​ 它虽然是复杂的,但它的最坏情况运行时间也是非常良好的,并且在实践中是高效的:它可以在 O(log n)时间内做查找、插入和删除,这里的n是树中元素的数目。

红黑树是每个节点都带有颜色属性的二叉查找树,颜色是红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
性质1.每个节点是红色或黑色。
性质2.根节点是黑色。
性质3.每个叶节点(NIL)是黑色。
性质4每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)性质5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

这些约束强制了红黑树的关键性质:从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
是性质3导致路径上不能有两个连续的红色节点确保了这个结果。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据性质4所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。
思考:为什么满足上面的性质,红黑树就能保证:其最长路径中节点个数不会超过最短路径节点个数的两倍?

应用
  • Linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块。
  • epoll在内核中的实现,用红黑树管理事件块。
  • nginx中,用红黑树管理timer等。
  • STL中的 map, set,mutil_map,mutil_set关联容器。
  • Java的TreeMap 实现
和AVL树的区别

3.7 AVL树与RB树的比较问题: RBTree 实现的功能都可以用AVL树是代替,那么为什么还需要引入RBTree呢?

  1. n个节点的深度是AVL2/3log;(n+1),RB树的深度2· log2(n +1).

  2. 红黑树不追求"“完全平衡”,即不像AVL那样要求节点的|balance|<= 1,它只要求部分达到平衡,但是提出了为节点增加颜色,红黑是用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。

  3. 就插入节点导致树失衡的情况,AVL和RBTree都是最多两次树旋转来实现复衡re_balance,旋转的量级是O(1)。

  4. 删除节点导致失衡,AVL需要维护从被删除节点到根节点root这条路径上所有节点的平衡,旋转的量级为0(logN)(我的观点是插入更新时:如当前节点的高度没有改变,则上面所有父节点的高度和平衡也不会改变。删除更新时:如当前节点的高度没有改变且平衡值在〔[-1,1]区间,则所有父节点的高度和平衡都不会改变。根据这两个推论,AVL的插入和删除大部分时候只需要向上回溯两到三层即呵,范围十分紧凑。)

  5. RB-Tree最多只需要旋转3次实现复衡,只需O(1),所以说RBTree删除节点的re_balance的效率更高,开销更小!(但是颜色更新会回溯到根节点,时间O(IogN) ).

  6. AVL树的结构相较于RBTree更为平衡,插入和删除引起失衡,如3,4所述,RBTree.复衡效率更高;当然,由于AVL高度平衡,因此AML的Search效率更高啦。

  7. 针对插入和删除节点导致失衡后的re_balance操作,红黑树能够提供一个比较*便宜"的解决方案,降低开销,是对search,insert ,以及delete效率的折衷,总体来说,RBTree的统计性能高于AVL,故引入RBTree是功能、性能、空间开销的折中结果。

  8. AVL更平衡,结构上更加直观,时间效能针对读取而言更高;维护稍慢,空间开销较大。红黑树,读取略逊于AVL,维护强于AVL,空间开销与AVL类似,内容极多时略优于AVL,维护优于AVL。
    基本上主要的几种平衡树看来,红黑树有着良好的稳定性和完整的功能,性能表现也很不错,综合实力强,在诸如STL的场景中需要稳定表现。

​ 红黑树的查询性能略微逊色于AVL树,因为其比AVL树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的AVL树最多多一次比较,但是,红黑树在插入和删除上优于AVL树,AVL树每次插入册除会进行大量的平衡度计算,而红黑树为了维持红黑性质所做的红黑变换和旋转的开销,相较于AVL树为了维持平衡的开销要小得多总结:实际应用中,若搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择RBTree。

B树和B+树

1.B树就是B-Tree。B-Tree 的定义:1/如: M= 5;
一棵m 阶B-Tree是一棵m路搜索树,它或者是空树,或者是满足下列性质的树:1.根结点子女数(子树)为[ 2,m ];
2.除根结点和叶节点以外的所有分支结点至少有[「m/21 ,m]个子女(子树);3.所有的叶节结点都位于同一层。
4.m阶B-Tree的节点结构如下:
n,So, (K1,S1). (K2, S2 ). … ( Kn, Sn)
其中,Si是指向子树的指针,0 <isn <m;K是关键码,1 ≤isn <m。Ki<Kit1, 1si < n。
·在子树S中所有的关键码都小于Ki+1,且大于K,0 <i < n。
·在子树Sn中所有的关键码都大于Kn;
·在子树So中的所有关键码都小于K1…子树S也是m路搜索树,0≤i≤ n.
事实上,在B_树的每个结点中还包含有一组指针D[m],指向实际对象的存放地址。
K[与 Dl(1≤isn < m)形成一个索引项(K[i],D[li]),通过K[i]可找到某个对象的存储地址D们。

1.2B-Tree的一些特点:
1、根节点关键字个数是:[1,m-1];非根节点的关键字的个是[Lm/2] , m -1];
2、关键字集合分布在整颗树中;/3、任何一个关键字出现一次,且只出现在一个结点中;(关键字不容许重复)

4、搜索有可能在非叶子结点结束;
5、其搜索性能等价于在关键字全集内做一次二分查找;

4B+Tree的定义:
B+Tree是B-Tree的一个升级版,相对于B-Tree树来说B+Tree树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。为什么说B+Tree树查找的效率要比B-Tree更高、更稳定。
规则:

二者不同:

逻辑上很近的节点,物理上很远

  1. B+跟B树不同B+树的非叶子节点不保存关键字记录的指针,只进行数据索引,这样使得B+树每个非叶子节点所能保存的关键字大大增加;
  2. B+树叶子节点保存了父节点的所有关键字记录的指针,所有数据地址必须要到叶子节点才能获取到。所以每次数据查询的次数都一样;
  3. B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。
  4. 非叶子节点的子节点数=关键字数(来源百度百科)(根据各种资料这里有两种算法的实现方式,另一种为非叶节点的关键字数=子节点数-1(来源维基百科),虽然他们数据排列结构不一样,但其原理还是一样的Mysql的B+树是用第一种方式实现);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值