jdk源码——集合(红黑树)

     强烈推荐一个网站,可以具体直观的查看红黑树的插入过程。

     点击(自己动手,丰衣足食)——>红黑树。

   上面这个网站,其实就是TreeMap的jdk源码的一种使用。

    md,看源码的时候,我才发现我的理解错了,虽然结论没有错,但是例子错了,真的错了。我下面的例子,从一开始就是错的,我以为随手画一个树,图上红或黑色,只要符合红黑树的五个特性就可以了,我在看源代码的时候,与自己以前想的不太一样,特别是根据自己在这篇文章中举的那个例子,在配上源码,进行了一次添加操作,感觉不对,所以,肯定不是源码的问题了,那就是自己的问题了。

   红黑树,不是随便一个平衡二叉树设置颜色,符合五个特性就是红黑树了。所以,网上的例子,大家要小心了,一不小心,就入坑了,而且不好出来啊。

   我上面给了一个链接,大家可以自己插入几个数。根据结论,自己分析一下就可以了。

    红黑树,从添加第一个节点,就已经开始经过变色,旋转等操作。所以,一直是红黑树结构。

     前面几篇文章,已经分析了ArrayList和LinkedList集合的源码了,还有set集合和Map集合没有分析,但是set集合的底层是Map,Map底层是红黑树,所以,后面的分析顺序是,先Map,后Set。

      当然这一篇,还是大致介绍一下红黑树。我的水平很有限,也是在网上查的资料,我仅仅是简单的介绍,如果想深入了解的化,大家还是去网上查资料吧,网上的讲解真的很好,我看的时候,有一点数据结构的基础,还是一脸懵逼,所以就在网上找了一个讲解红黑树的视频看,结果视频中将的都是错的,本来懵逼的我更懵逼了。所以最好找一点比较严谨的资料看。

      其实我是真不想误人子弟,所以劝大家还是找更好的资料看。好像网上有一个麻省理工的公开课,讲解的就是红黑树,只不过是全英讲解,你要是英语还可以的话,可以去看一下。

      好了,红黑树正式开始了!

     红黑树是一种特殊的平衡二叉树,效率最高的平衡二叉树的是avl树,深度只差不差过1倍,插入元素较为复杂

     红黑树比avl树的效率略低一点,深度只差不超过2倍

     红黑树的特性(五条),只有符合这五条,才可以称之为红黑树

        1.所有节点都是红色或者黑色

        2.根节点总是黑色,root节点是黑色

        3.如果节点是红色的,子节点必须是黑色的(两个红色节点不可能连续)

       4.从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)(条件4限制了深度只差不  超过2倍)

        5.插入的节点都是红色的

    大家可以看一下下面这个图:

                                                                            图一错的


        1.根据本图,可以看到所有的节点都是红色或者是黑色

        2.36为root节点,必须是黑色

        3.18,54,8,13节点为红色,则子节点必须是黑色,不能是红色

       4.root节点到每个叶子结点的路径都包含相同的黑色节点,如36-18-10-8-NIL,包含3个黑色节点,如36-54-41-NIL,也包含3个黑色节点

        5.插入的节点都是红色

        所以红黑树,必须符合上面5个条件

    如果按照严格的红黑树步骤进行添加,同样是上面的数据,下面是正确的红黑树结构。



        当我们进行添加操作时,会有三种方式进行数据的调整:

               1.变色

               2.左旋

               3.右旋

      ——变色(变色分为两种情况)

                                                                         图二(图一部分图)  ,就是这个意思


            1.插入节点的父辈节点都是红色,则将父辈节点都变为黑色,祖父节点变为红色

               图2是图一的左下面部分,当插入一个节点5,5节点的父辈8和13都是红色,则变为黑色,5节点的祖父节点变为10变为红色,如2所示

              但是,如果10节点是root节点,此时则不能变色来维护红黑树结构。

          2.将祖父节点变为红色。(此时,祖父以下节点已符合红黑树特性),此时祖父节点变为当前节点,查看是否符合特性,如果不符合,

          继续改变(有种递归特性,从下到上,节点逐渐变少,更好控制),最终,要改变的都是根节点(最上面的那个节点)

                                                                          图三(图一部分图) 

                                                   如果36为root节点时,这张图是不能进行变色操作的

          

              经过1的操作,10节点已经变为红色节点,10节点变为当前节点,父辈节点为18和54节点都为红色,如果依照1操作,将18,54节点变为黑色,36节点变为红色,此时已经违背了根节点只能为黑色的这个条件,所以这样是不行的。

            此时,36节点为根节点,为红色,违背了红黑树的5个条件中的根节点只能为黑色。这就是上面结论中说的,最终都是要改变root节点。

            那么,该怎么办呢?

            此时,就要考虑旋转操作了。

     ——旋转

          该如何旋转呢?

          请看一下下面这张图,这张图,是新图,并不是图一的部分图,

                                                                       图四

              


图五(图一部分图)            

                    看过这两张图,应该知道左旋和右旋是怎么一回事了吧?这两张图,仅仅表示了旋转,并没有在红黑树的结构下进行旋转,只是旋转。

                   下面,我们介绍在红黑树下是如何进行旋转的。

          经过变色阶段,此时树的矛盾都集中在最上端,此时怎么办呢?
          只能通过旋转了,旋转,都是向黑色的兄弟节点方向旋转
       左旋:
           当前节点是右孩子,父节点是红色,父节点兄弟节点是黑色,只能左旋
              1.将父节点当做新的当前节点,
              2.以新的当前节点作为支点进行左旋,中间的分支,连接到左边

       右旋:
           当前节点是左孩子,父节点是红色,父节点兄弟节点是黑色,只能右旋
                1.将父节点变为黑色

                2.祖父节点设为红色

                3.以祖父节点当做支点,进行右旋

          以图一为例子,进行完整的维护:

                                 

 图六错的



                  右旋,需要旋转的同时还要变色,左旋,只进行旋转而不需要变色。

  

        好了,红黑树就将这么多吧,仅仅只是简单介绍一下,有可能其中会有错误,还请指正。

       这仅仅是红黑树添加的情况,删除的情况比这个感觉要复杂,到时候分析到TreeMap的时候,根据代码可以得出红黑树删除的操作。

      我还是想说,我写的仅供参考,最好找一些大牛写的文章。我是真的不想误人子弟..........


     

猜你喜欢

转载自blog.csdn.net/qq_36838854/article/details/80323567