zoukankan      html  css  js  c++  java
  • TreeMap的实现--红黑树

    http://cmsblogs.com/?p=1013  原文出处。

    TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap的实现,但是为了与Java提高篇系列博文保持一致还是叫做TreeMap比较好。通过这篇博文你可以获得如下知识点:

           1、红黑树的基本概念。

           2、红黑树增加节点、删除节点的实现过程。

           3、红黑树左旋转、右旋转的复杂过程。

           4、Java 中TreeMap是如何通过put、deleteEntry两个来实现红黑树增加、删除节点的。

    我想通过这篇博文你对TreeMap一定有了更深的认识。好了,下面先简单普及红黑树知识。

           一、红黑树简介

           红黑树又称红-黑二叉树,它首先是一颗二叉树,它具体二叉树所有的特性。同时红黑树更是一颗自平衡的排序二叉树。

           我们知道一颗基本的二叉树他们都需要满足一个基本性质--即树中的任何节点的值大于它的左子节点,且小于它的右子节点。按照这个基本性质使得树的检索效率大大提高。我们知道在生成二叉树的过程是非常容易失衡的,最坏的情况就是一边倒(只有右/左子树),这样势必会导致二叉树的检索效率大大降低(O(n)),所以为了维持二叉树的平衡,大牛们提出了各种实现的算法,如:AVLSBT伸展树TREAP ,红黑树等等。

           平衡二叉树必须具备如下特性:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。也就是说该二叉树的任何一个等等子节点,其左右子树的高度都相近。

           红黑树顾名思义就是节点是红色或者黑色的平衡二叉树,它通过颜色的约束来维持着二叉树的平衡。对于一棵有效的红黑树二叉树而言我们必须增加如下规则:

           1、每个节点都只能是红色或者黑色

           2、根节点是黑色

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

           4、如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。

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

           这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这棵树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。所以红黑树它是复杂而高效的,其检索效率O(log n)。下图为一颗典型的红黑二叉树。

           对于红黑二叉树而言它主要包括三大基本操作:左旋、右旋、着色。

    左旋                                   右旋

     

       二、TreeMap数据结构

           >>>>>>回归主角:TreeMap<<<<<<

           TreeMap的定义如下:

    public class TreeMap<K,V>
        extends AbstractMap<K,V>
        implements NavigableMap<K,V>, Cloneable, java.io.Serializable

           TreeMap继承AbstractMap,实现NavigableMap、Cloneable、Serializable三个接口。其中AbstractMap表明TreeMap为一个Map即支持key-value的集合, NavigableMap(更多)则意味着它支持一系列的导航方法,具备针对给定搜索目标返回最接近匹配项的导航方法 。

           TreeMap中同时也包含了如下几个重要的属性:

    //比较器,因为TreeMap是有序的,通过comparator接口我们可以对TreeMap的内部排序进行精密的控制
            private final Comparator<? super K> comparator;
            //TreeMap红-黑节点,为TreeMap的内部类
            private transient Entry<K,V> root = null;
            //容器大小
            private transient int size = 0;
            //TreeMap修改次数
            private transient int modCount = 0;
            //红黑树的节点颜色--红色
            private static final boolean RED = false;
            //红黑树的节点颜色--黑色
            private static final boolean BLACK = true;

           对于叶子节点Entry是TreeMap的内部类,它有几个重要的属性:

    //键
            K key;
            //值
            V value;
            //左孩子
            Entry<K,V> left = null;
            //右孩子
            Entry<K,V> right = null;
            //父亲
            Entry<K,V> parent;
            //颜色
            boolean color = BLACK;

           注:前面只是开胃菜,下面是本篇博文的重中之重,在下面两节我将重点讲解treeMap的put()、delete()方法。通过这两个方法我们会了解红黑树增加、删除节点的核心算法。

           三、TreeMap put()方法

           在了解TreeMap的put()方法之前,我们先了解红黑树增加节点的算法。

           红黑树增加节点

           红黑树在新增节点过程中比较复杂,复杂归复杂它同样必须要依据上面提到的五点规范,同时由于规则1、2、3基本都会满足,下面我们主要讨论规则4、5。假设我们这里有一棵最简单的树,我们规定新增的节点为N、它的父节点为P、P的兄弟节点为U、P的父节点为G。

           对于新节点的插入有如下三个关键地方:

           1、插入新节点总是红色节点 。

           2、如果插入节点的父节点是黑色, 能维持性质 。

           3、如果插入节点的父节点是红色, 破坏了性质. 故插入算法就是通过重新着色或旋转, 来维持性质 。

           为了保证下面的阐述更加清晰和根据便于参考,我这里将红黑树的五点规定再贴一遍:

    1、每个节点都只能是红色或者黑色

    2、根节点是黑色

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

    4、如果一个结点是红的,则它两个子节点都是黑的。也就是说在一条路径上不能出现相邻的两个红色结点。

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

     

    •        一、为跟节点
    •        若新插入的节点N没有父节点,则直接当做根据节点插入即可,同时将颜色设置为黑色。(如图一(1))

             二、父节点为黑色

             这种情况新节点N同样是直接插入,同时颜色为红色,由于根据规则四它会存在两个黑色的叶子节点,值为null。同时由于新增节点N为红色,所以通过它的子节点的路径依然会保存着相同的黑色节点数,同样满足规则5。(如图一(2))

      (图一)

             三、若父节点P和P的兄弟节点U都为红色

             对于这种情况若直接插入肯定会出现不平衡现象。怎么处理?P、U节点变黑、G节点变红。这时由于经过节点P、U的路径都必须经过G所以在这些路径上面的黑节点数目还是相同的。但是经过上面的处理,可能G节点的父节点也是红色,这个时候我们需要将G节点当做新增节点递归处理。

             四、若父节点P为红色,叔父节点U为黑色或者缺少,且新增节点N为P节点的右孩子

             对于这种情况我们对新增节点N、P进行一次左旋转。这里所产生的结果其实并没有完成,还不是平衡的(违反了规则四),这是我们需要进行情况5的操作。

    •        五、父节点P为红色,叔父节点U为黑色或者缺少,新增节点N为父节点P左孩子

    •        这种情况有可能是由于情况四而产生的,也有可能不是。对于这种情况先已P节点为中心进行右旋转,在旋转后产生的树中,节点P是节点N、G的父节点。但是这棵树并不规范,它违反了规则4,所以我们将P、G节点的颜色进行交换,使之其满足规范。开始时所有的路径都需要经过G其他们的黑色节点数一样,但是现在所有的路径改为经过P,且P为整棵树的唯一黑色节点,所以调整后的树同样满足规范5。

      •        上面展示了红黑树新增节点的五种情况,这五种情况涵盖了所有的新增可能,不管这棵红黑树多么复杂,都可以根据这五种情况来进行生成。下面就来分析Java中的TreeMap是如何来实现红黑树的。

  • 相关阅读:
    SQL函数说明大全
    (火炬)MS SQL Server数据库案例教程
    SQL 数据库基础语句
    java 中length,length(),size()的区别
    关于webLogic启动问题
    dreamweaver读jsp时遇到的问题
    Microsoft 注册表编辑器 (regedit.exe)
    由正则表达式REGEXP_REPLACE开始
    Hello World
    Python基础目录
  • 原文地址:https://www.cnblogs.com/icbcfang/p/5460926.html
Copyright © 2011-2022 走看看