数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树

一 二叉树
树的概念:
树是一种 非线性 的数据结构,它是由 n ( n>=0 )个有限结点组成一个具有层次关系的集合。 把它叫做树是因为它看 起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的 。
二叉树(binary tree)是指树中结点的度不大于2的有序树,它是一种最简单且最重要的树。二叉树的递归定义为:二叉树是一棵空树,或者是一棵由一个根节点和两棵互不相交的,分别称作根的左子树和右子树组成的非空树;左子树和右子树又同样都是二叉树 。
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片

两种特殊的二叉树:
一棵深度为k,且有2^k-1个节点的二叉树,称为满二叉树。这种树的特点是每一层上的节点数都是最大节点数。而在一棵二叉树中,除最后一层外,若其余层都是满的,或者说在最后一层右边缺少连续若干节点,则此二叉树为完全二叉树,深度为k的完全二叉树,至少有2^(k-1)个叶子节点,至多有2^k-1个节点。
二 二叉查找树
二叉树具有以下性质:左子树的键值小于根的键值,右子树的键值大于根的键值。如下图:
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片

对该二叉树的节点进行查找发现深度为1的节点的查找次数为1,深度为2的查找次数为2,深度为n的节点的查找次数为n。
三 平衡二叉树(AVL Tree)
平衡二叉树(AVL树)在符合二叉查找树的条件下,还满足任何节点的两个子树的高度最大差为1。下面的两张图片,左边是AVL树,它的任何节点的两个子树的高度差<=1;右边的不是AVL树,其根节点的左子树高度为3,而右子树高度为1;
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片

如果在AVL树中进行插入或删除节点,可能导致AVL树失去平衡,这种失去平衡的二叉树可以概括为四种姿态:LL(左左)、RR(右右)、LR(左右)、RL(右左)。它们的示意图如下:
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片

这四种失去平衡的姿态都有各自的定义:
LL:LeftLeft,也称“左左”。插入或删除一个节点后,根节点的左孩子(Left Child)的左孩子(Left Child)还有非空节点,导致根节点的左子树高度比右子树高度高2,AVL树失去平衡。
RR:RightRight,也称“右右”。插入或删除一个节点后,根节点的右孩子(Right Child)的右孩子(Right Child)还有非空节点,导致根节点的右子树高度比左子树高度高2,AVL树失去平衡。
LR:LeftRight,也称“左右”。插入或删除一个节点后,根节点的左孩子(Left Child)的右孩子(Right Child)还有非空节点,导致根节点的左子树高度比右子树高度高2,AVL树失去平衡。
RL:RightLeft,也称“右左”。插入或删除一个节点后,根节点的右孩子(Right Child)的左孩子(Left Child)还有非空节点,导致根节点的右子树高度比左子树高度高2,AVL树失去平衡。
AVL树失去平衡之后,可以通过旋转使其恢复平衡。
LL的旋转。LL失去平衡的情况下,可以通过一次旋转让AVL树恢复平衡。步骤如下:

  1. 将根节点的左孩子作为新根节点。
  2. 将新根节点的右孩子作为原根节点的左孩子。
  3. 将原根节点作为新根节点的右孩子。
LL旋转示意图如下:
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片

RR的旋转:RR失去平衡的情况下,旋转方法与LL旋转对称,步骤如下:
  1. 将根节点的右孩子作为新根节点。
  2. 将新根节点的左孩子作为原根节点的右孩子。
  3. 将原根节点作为新根节点的左孩子。
RR旋转示意图如下:
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片

LR的旋转:LR失去平衡的情况下,需要进行两次旋转,步骤如下:
  1. 围绕根节点的左孩子进行RR旋转。
  2. 围绕根节点进行LL旋转。
LR的旋转示意图如下:
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片


RL的旋转:RL失去平衡的情况下也需要进行两次旋转,旋转方法与LR旋转对称,步骤如下:
  1. 围绕根节点的右孩子进行LL旋转。
  2. 围绕根节点进行RR旋转。
RL的旋转示意图如下:
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片

四 红黑树
有了二叉搜索树,为什么还需要平衡二叉树?
在学习二叉搜索树、平衡二叉树时,我们不止一次提到,二叉搜索树容易退化成一条链
这时,查找的时间复杂度从O ( l o g 2 N ) O(log_2N)O(log 2N)也将退化成O ( N ) O(N)O(N)
引入对左右子树高度差有限制的平衡二叉树,保证查找操作的最坏时间复杂度也为O ( l o g 2 N ) O(log_2N)O(log 2N)。

有了平衡二叉树,为什么还需要红黑树?
AVL的左右子树高度差不能超过1,每次进行插入/删除操作时,几乎都需要通过旋转操作保持平衡
在频繁进行插入/删除的场景中,频繁的旋转操作使得AVL的性能大打折扣
红黑树通过牺牲严格的平衡,换取插入/删除时少量的旋转操作,整体性能优于AVL
红黑树插入时的不平衡,不超过两次旋转就可以解决;删除时的不平衡,不超过三次旋转就能解决
红黑树的红黑规则,保证最坏的情况下,也能在O ( l o g 2 N ) O(log_2N)O(log 2N)时间内完成查找操作。
红黑规则
一棵典型的红黑树,如图所示
数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树
文章图片

从图示,可以发现红黑树的一些规律:
节点不是红色就是黑色,根节点是黑色
红黑树的叶子节点并非传统的叶子节点,红黑树的叶子节点是null节点(空节点)且为黑色
同一路径,不存在连续的红色节点
以上是我们能发现的一些规律,这些规律其实是红黑规则的一部分。

红黑规则
【数据结构|数据结构 - 二叉树,二叉查找树,平衡二叉树,红黑树】节点不是黑色,就是红色(非黑即红)
根节点为黑色
叶节点为黑色(叶节点是指末梢的空节点 Nil或Null)
一个节点为红色,则其两个子节点必须是黑色的(根到叶子的所有路径,不可能存在两个连续的红色节点)
每个节点到叶子节点的所有路径,都包含相同数目的黑色节点(相同的黑色高度)。

    推荐阅读