树的高度从零还是一开始数_AVL树 vs 红黑树

38fef0c9b35fd7db6dfa99fb1b18c04b.png

1.导读

d12ce7293740b5fcb66f0071c951199b.png

链表和数组属于数据结构中的线性结构,其搜索时间复杂度为O(n),在最坏的情况下,我们必须遍历整个表才能找到所需的元素。有没有更高效的数据结构呢?本章我们开始介绍数据结构中的树形结构。

1a4194c1e4df98a7dac4aa88a8f6425e.png

2.树(Tree)

树是一种数据结构,除了保留一些数据之外,每个项目都保留其对子项及其父项的引用(指针)。

ff149925982303d47b6cc2ad3f365071.png

e7bfbdc53918be1b2b3d6bdc43dc9833.png

以下是关于树的重要术语。

  • 路径 - 路径是指沿树边缘的节点序列。
  • 根节点 - 树顶部的节点称为根节点(Root)。每个树只有一个根,从根节点到任何节点只有一条路径。
  • 父节点 - 除根节点外的任何节点都有一条边向上的称为父节点的节点(Parent Node)。
  • 子节点 - 给定节点下面的节点,由其边缘向下连接称为其子节点(Child Node)。
  • 叶子节点 - 没有任何子节点的节点称为叶子节点(Leaf Node)。
  • 子树 - 子树表示节点的后代(Sub-tree)。
  • 访问 - 访问是指当控制在节点上时检查节点的值。
  • 遍历 - 遍历意味着以特定顺序遍历节点。
  • 级别 - 节点级别表示节点的层数。如果根节点处于级别0,则其下一个子节点处于级别1,其孙级处于级别2,依此类推。
  • Keys - Key表示节点的值,基于该节点对节点执行搜索操作。

3.二叉树(Binary Tree)

二叉树是一种特定的树,二叉树每个节点最多可以有两个子节点(左子树和右子树),而树的每个节点可以有任意数量的子节点。

ab629a1740c6cc6184a468d5ec63ded5.png

构造二叉树并不困难,它与构建链表非常相似,但是二叉树在搜索方面不比任何其他树或其他数据结构有更好搜索性能,都是O(n)。如果元素没有按特定顺序放置,我们必须遍历整个树才能搜索到想要的元素。所以我们必须要对元素进行排序,以改善搜索性能,二叉搜索树就是进行了排序的特定二叉树。

4.二叉搜索树(Binary Search Tree)

二叉搜索树是一种特定的二叉树,其中每个项在右边保留较大的元素,而较小的项在左侧。二叉搜树有以下特征:

  • 每个节点有一个key,并且任意两个节点的key都不同;因此,所有的key都是唯一的。
  • 在根节点的左子树中,节点的key都小于根节点的key。
  • 在根节点的右子树中,节点的key都大于根节点的key。
  • 根节点的左、右子树都是二叉搜索树。

84f96b2991151c887d3d094dbfc3537a.png

插入二叉树相当容易,我们只要通过将值与从根节点开始与每个值进行比较,根据值是小于或大于节点的值决定去哪里(左或右)。

0c9c90e6de6a20a7d7d24e079b18d4d3.png

平均情况下,在二叉搜索树中搜索O(log n)应该比搜索链表和普通二叉树O(n)要快。

ed2cefe1a77ac0c1a0ed22836187a6f0.png

二叉搜索树在最差情况下,如果出现节点都在根的一侧,则搜索与链表一样慢,都是O(n)。所以我们需要关心如何使二叉搜索树保持平衡,以改善最差情况下搜索性能,由此出现了平衡二叉搜索树。

3407dfbb567478d6142662a133ee1b52.png

从上图可以发现,链表可以理解为是一颗特别的树,其节点都在根的一侧。

5.平衡二叉搜索树(Balanced Binary Tree)

如果搜索树的高度总是O(log n),我们就能保证搜索、插入和删除的时间为O(log n)。最坏情况下的高度为O(log n)的树称为平衡树(Balanced Tree)。平衡二叉搜索树的最大高度是log n,因此最坏情况搜索时间复杂度为O(log n),但相比二叉搜索树,它需要更多的时间来构建和维护(插入与删除)。介绍两种常用的平衡二叉搜索树,AVL树与红黑树。

87ff3b6dc2080b341b5836fde206c2b4.png

5.1.AVL树(AVL Tree)

以他们的发明者Adelson,Velski和Landis命名,AVL树是高度平衡二叉搜索树。AVL树检查左侧和右侧子树的高度,并确保差异不大于1。在这里,我们看的第一颗树是平衡的,接下来的两棵树是不平衡的。

6e92fe52ed324166e97c2462877274ba.png

在第二颗树中,C的左子树高度为2,右子树的高度为0,因此差异为2。在第三颗树中,A的右子树的高度为2而左侧缺失,因此它为0,差异又是2。AVL树允许差异(平衡因子)仅为1。

BalanceFactor = height(left-subtree) - height(right-subtree)

如果左子树和右子树的高度差异大于1,则使用一些旋转技术来平衡。为了平衡自身,AVL树可以执行一下四种旋转:

  • 左旋
  • 右旋
  • 左右旋
  • 右左旋

左旋

如果树变得不平衡,当一个节点插入到右子树的右子树中时,我们执行一个左旋转。

7178211d04f3cce6831939ca0e5ec385.png

在我们的示例中,节点A变得不平衡,因此节点插入到A右子树的右子树中。我们通过使A成为B的左子树来执行左旋转。

右旋

如果节点插入左子树的左子树中,则AVL树可能变得不平衡。然后树需要正确的旋转。

d84615907b3cc7719b43fabd4f61a03f.png

如图所示,通过执行右旋转,不平衡节点成为其左孩子的右孩子。

左右旋

左右旋转是左旋转然后右旋转的组合。

dba2441e98a49e8b1791e15e8c133e9e.png

1、已将节点插入左子树的右子树中。这使得C成为不平衡节点,这种场景导致AVL树执行左右旋转。

2、我们首先在C的左子树上执行左旋转。这使得A成为B的左子树。

3、节点C仍然是不平衡的。

4、我们现在将右旋转树,使B成为此子树的新根节点。C现在成为其左子树的右子树。

5、树现在平衡了。

右左旋

右左旋转是右旋转然后左旋转的组合。

4b5228818fa7b52288ac9e83217ff04e.png

1、已将节点插入右子树的左子树中。这使得A是一个平衡因子为2的不平衡节点。

2、首先,我们沿着C节点执行正确的旋转,使C成为其自己的左子树B的右子树。现在,B成为A的正确子树。

3、由于右子树的右子树并且需要左旋转,节点A仍然是不平衡的。

4、通过使B成为子树的新根节点来执行左旋转,A成为其右子树B的左子树。

5、树现在平衡了。

5.2.红黑树(Red Black Tree)

红黑树是一种特殊的二叉搜索树,其中每个树的节点存储一种颜色,红色或黑色。红黑树是一种自平衡二叉搜索树,其中插入或删除操作是智能完成的,以确保树始终是平衡的。红黑树中任何操作(例如搜索、插入或删除)的时间复杂度都是O(log n),其中n是红黑树中的节点数。

70266433ab487aa8edcdaaeb8c6e9d14.png

任何有效的红黑树有如下的要求:

1、节点要么是红色,要么是黑色。

2、根节点是黑色。

3、每个叶子节点(NIL节点,空节点)是黑色的。

4、每个红色节点的两个子节点都是黑色(即从每个叶子到根的所有路径上不能有两个连续的红色节点)。

5、从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和搜索某个值的最坏情况时间都要求与树的高度成比例,这个高度在理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉搜索树。这个特性是如何确保的?注意性质4导致了路径不能有两个毗连的红色节点,最短的可能路径都是黑色(x个)节点,最长的可能路径有交替的红色(y个)和黑色(y个)节点(共2y)。因为根据性质5所有最长的路径都有相同数目的黑色节点(x == y),这就表明了没有路径能多于任何其他路径的两倍长。

5.3 AVL树 vs 红黑树

AVL树是严格的平衡二叉搜索树,平衡条件必须满足所有节点的左右子树高度差不超过1。不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时的,由此我们可以知道AVL树合适用于插入与删除次数比较少,但搜索多的情况。AVL树在Windows NT内核中广泛被使用。

红黑树是一种平衡二叉搜索树(红黑树确保没有一条路径比其它路径长出两倍),由于是弱平衡,可以看出,在相同的节点情况下,AVL树的高度低于红黑树,相对于要求严格的AVL树来说,它的旋转次数少,所以对于插入与删除较多的情况,我们就用红黑树。红黑树广泛用于C++的STL中,map和set都是用红黑树实现的。

6.性能

64ffdc67f858c772ab3c770cc04bc39a.png

dd3f1e985737b7fdb1c5c1e759846824.png
l7dpi微信公共号
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值