服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java红黑树的数据结构与算法解析

Java红黑树的数据结构与算法解析

2021-11-14 11:53伯努力不努力 Java教程

红黑树问题是各大计算机考研命题以及面试算法题目中的热门,接下来我们为大家图解红黑树的数据结构与算法解析,需要的朋友可以参考下

红黑树的介绍

红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树。

红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值。

除了具备该特性之外,红黑树还包括许多额外的信息。

红黑树的每个节点上都有存储位表示节点的颜色,颜色是红(Red)或黑(Black)。

红黑树的特性:

(1) 每个节点或者是黑色,或者是红色。

(2) 根节点是黑色。

(3) 每个叶子节点是黑色。 [注意:这里叶子节点,是指为空的叶子节点!]

(4) 如果一个节点是红色的,则它的子节点必须是黑色的。

(5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

关于它的特性,需要注意的是:

第一,特性(3)中的叶子节点,是只为空(NIL或null)的节点。

第二,特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。

红黑树的主要是想对2-3查找树进行编码,尤其是对2-3查找树中的3-nodes节点添加额外的信息。红黑树中将节点之间的链接分为两种不同类型,红色链接,他用来链接两个2-nodes节点来表示一个3-nodes节点。黑色链接用来链接普通的2-3节点。特别的,使用红色链接的两个2-nodes来表示一个3-nodes节点,并且向左倾斜,即一个2-node是另一个2-node的左子节点。这种做法的好处是查找的时候不用做任何修改,和普通的二叉查找树相同。

Java红黑树的数据结构与算法解析

根据以上描述,红黑树定义如下:

红黑树是一种具有红色和黑色链接的平衡查找树,同时满足:

1.红色节点向左倾斜
2.一个节点不可能有两个红色链接
3.整个树完全黑色平衡,即从根节点到所以叶子结点的路径上,黑色链接的个数都相同。

下图可以看到红黑树其实是2-3树的另外一种表现形式:如果我们将红色的连线水平绘制,那么他链接的两个2-node节点就是2-3树中的一个3-node节点了。

Java红黑树的数据结构与算法解析

红黑树的实现

1.节点

我们可以在二叉查找树的每一个节点上增加一个新的表示颜色的标记。该标记指示该节点指向其父节点的颜色。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private class Node {
        Node left, right;//左右子树
        TKey key;//键
        TValue value;//相关联的值
        int n;//这颗子树中的节点总数
        boolean color;//由父节点指向它的连接的颜色
 
 
        public Node(TKey key, TValue value, int number, boolean color) {
            this.key = key;
            this.value = value;
            this.n = number;
            this.color = color;
        }
    }
 
    private boolean isRed(Node node) {
        if (node == null) return false;
        return node.color == RED;
    }

Java红黑树的数据结构与算法解析

2.查找

红黑树是一种特殊的二叉查找树,他的查找方法也和二叉查找树一样,不需要做太多更改。

但是由于红黑树比一般的二叉查找树具有更好的平衡,所以查找起来更快。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//查找获取指定的值
    public TValue get(TKey key) {
        return getValue(root, key);
    }
 
    private TValue getValue(Node node, TKey key) {
        if (node == null) return null;
        int cmp = key.compareTo(node.Key);
        if (cmp == 0) {
            return node.value;
        } else if (cmp > 0) {
            return getValue(node.right, key);
        } else {
            return getValue(node.left, key);
        }
    }

3.平衡化

在介绍插入之前,我们先介绍如何让红黑树保持平衡,因为一般的,我们插入完成之后,需要对树进行平衡化操作以使其满足平衡化。

旋转

旋转又分为左旋和右旋。通常左旋操作用于将一个向右倾斜的红色链接旋转为向左链接。对比操作前后,可以看出,该操作实际上是将红线链接的两个节点中的一个较大的节点移动到根节点上。

左旋操作如下图:

Java红黑树的数据结构与算法解析

Java红黑树的数据结构与算法解析

?
1
2
3
4
5
6
7
8
9
10
11
12
13
//左旋转
  private Node rotateLeft(Node h) {
      Node x = h.right;
      //将x的左节点复制给h右节点
      h.right = x.left;
      //将h复制给x右节点
      x.left = h;
      x.color = h.color;
      h.color = RED;
      x.n = h.n;
      h.n = 1 + size(h.left) + size(h.right);
      return x;
  }

左旋的动画效果如下:

Java红黑树的数据结构与算法解析

右旋是左旋的逆操作,过程如下:

Java红黑树的数据结构与算法解析

Java红黑树的数据结构与算法解析

代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
//右旋转
  private Node rotateRight(Node h) {
      Node x = h.left;
      h.left = x.right;
      x.right = h;
 
      x.color = h.color;
      h.color = RED;
      x.n = h.n;
      h.n = 1 + size(h.left) + size(h.right);
      return x;
  }

右旋的动画效果如下:

Java红黑树的数据结构与算法解析

颜色反转

当出现一个临时的4-node的时候,即一个节点的两个子节点均为红色,如下图:

Java红黑树的数据结构与算法解析

Java红黑树的数据结构与算法解析

这其实是个A,E,S 4-node连接,我们需要将E提升至父节点,操作方法很简单,就是把E对子节点的连线设置为黑色,自己的颜色设置为红色。

有了以上基本操作方法之后,我们现在对应之前对2-3树的平衡操作来对红黑树进行平衡操作,这两者是可以一一对应的,如下图:

Java红黑树的数据结构与算法解析

现在来讨论各种情况:

Case 1 往一个2-node节点底部插入新的节点

先热身一下,首先我们看对于只有一个节点的红黑树,插入一个新的节点的操作:

Java红黑树的数据结构与算法解析

这种情况很简单,只需要:

1.标准的二叉查找树遍历即可。新插入的节点标记为红色

2.如果新插入的节点在父节点的右子节点,则需要进行左旋操作

Case 2往一个3-node节点底部插入新的节点

假设我们往一个只有两个节点的树中插入元素,如下图,根据待插入元素与已有元素的大小,又可以分为如下三种情况:

Java红黑树的数据结构与算法解析

1.如果带插入的节点比现有的两个节点都大,这种情况最简单。我们只需要将新插入的节点连接到右边子树上即可,然后将中间的元素提升至根节点。这样根节点的左右子树都是红色的节点了,我们只需要调研FlipColor方法即可。其他情况经过反转操作后都会和这一样。

2.如果插入的节点比最小的元素要小,那么将新节点添加到最左侧,这样就有两个连接红色的节点了,这是对中间节点进行右旋操作,使中间结点成为根节点。这是就转换到了第一种情况,这时候只需要再进行一次FlipColor操作即可。

3.如果插入的节点的值位于两个节点之间,那么将新节点插入到左侧节点的右子节点。因为该节点的右子节点是红色的,所以需要进行左旋操作。操作完之后就变成第二种情况了,再进行一次右旋,然后再调用FlipColor操作即可完成平衡操作。

有了以上基础,我们现在来总结一下往一个3-node节点底部插入新的节点的操作步骤,下面是一个典型的操作过程图:

Java红黑树的数据结构与算法解析

可以看出,操作步骤如下:

1.执行标准的二叉查找树插入操作,新插入的节点元素用红色标识。

2.如果需要对4-node节点进行旋转操作

3.如果需要,调用FlipColor方法将红色节点提升

4.如果需要,左旋操作使红色节点左倾。

5.在有些情况下,需要递归调用Case1 Case2,来进行递归操作。如下:

Java红黑树的数据结构与算法解析

?
1
2
3
4
5
void flipColors(Node h) {
        h.color = RED;
        h.left.color = BLACK;
        h.right.color = BLACK;
    }

插入的实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private Node put(Node h, TKey key, TValue value) {
      if (h == null) {
          return new Node(key, value, 1, RED);
      }
      int cmp = key.compareTo(h.key);
      if (cmp < 0) {
          h.left = put(h.left, key, value);
      } else if (cmp > 0) {
          h.right = put(h.right, key, value);
      } else {
          h.value = value;
      }
      if (isRed(h.right) && !isRed(h.left)) {
          h = rotateLeft(h);
      }
      if (isRed(h.left) && isRed(h.left.left)) {
          h = rotateRight(h);
      }
      if (isRed(h.left) && isRed(h.right)) {
          flipColors(h);
      }
      h.n = size(h.left) + size(h.right) + 1;
      return h;
  }

红黑树的复杂度–

对红黑树的分析其实就是对2-3查找树的分析,红黑树能够保证符号表的所有操作即使在最坏的情况下都能保证对数的时间复杂度,也就是树的高度。

1. 在最坏的情况下,红黑树的高度不超过2lgN

最坏的情况就是,红黑树中除了最左侧路径全部是由3-node节点组成,即红黑相间的路径长度是全黑路径长度的2倍。

下图是一个典型的红黑树,从中可以看到最长的路径(红黑相间的路径)是最短路径的2倍:

Java红黑树的数据结构与算法解析

2. 红黑树的平均高度大约为lgN

下图是红黑树在各种情况下的时间复杂度,可以看出红黑树是2-3查找树的一种实现,他能保证最坏情况下仍然具有对数的时间复杂度。

下图是红黑树各种操作的时间复杂度。

Java红黑树的数据结构与算法解析

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注服务器之家的更多内容!

原文链接:https://blog.csdn.net/u012124438/article/details/78200189

延伸 · 阅读

精彩推荐
  • Java教程Java BufferWriter写文件写不进去或缺失数据的解决

    Java BufferWriter写文件写不进去或缺失数据的解决

    这篇文章主要介绍了Java BufferWriter写文件写不进去或缺失数据的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代码

    小米推送Java代码

    今天小编就为大家分享一篇关于小米推送Java代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    富贵稳中求8032021-07-12
  • Java教程Java8中Stream使用的一个注意事项

    Java8中Stream使用的一个注意事项

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,但在使用中遇到了一个非常重要的注意点,所以这篇文章主要给大家介绍了关于Java8中S...

    阿杜7482021-02-04
  • Java教程Java实现抢红包功能

    Java实现抢红包功能

    这篇文章主要为大家详细介绍了Java实现抢红包功能,采用多线程模拟多人同时抢红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    littleschemer13532021-05-16
  • Java教程20个非常实用的Java程序代码片段

    20个非常实用的Java程序代码片段

    这篇文章主要为大家分享了20个非常实用的Java程序片段,对java开发项目有所帮助,感兴趣的小伙伴们可以参考一下 ...

    lijiao5352020-04-06
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    这篇文章主要介绍了Java使用SAX解析xml的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程xml与Java对象的转换详解

    xml与Java对象的转换详解

    这篇文章主要介绍了xml与Java对象的转换详解的相关资料,需要的朋友可以参考下...

    Java教程网2942020-09-17
  • Java教程升级IDEA后Lombok不能使用的解决方法

    升级IDEA后Lombok不能使用的解决方法

    最近看到提示IDEA提示升级,寻思已经有好久没有升过级了。升级完毕重启之后,突然发现好多错误,本文就来介绍一下如何解决,感兴趣的可以了解一下...

    程序猿DD9332021-10-08