一,前言

  TreeMap:基于红黑树实现的,TreeMap是有序的。

二,TreeMap结构

  2.1 红黑树结构

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

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

    红黑树的特点:

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

   2、根节点是黑色

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

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

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

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

     

      对于红黑树的其他内容可以参照:http://www.cnblogs.com/yangecnu/p/Introduce-Red-Black-Tree.html

  2.2 TreeMap红黑树节点

   前面已经说个TreeMap是基于红黑树结构实现的。如下是JDK中红黑树节点的代码:

static final class Entry<K,V> implements Map.Entry<K,V> {
K key; //键
V value; //值
Entry<K,V> left = null; //左孩子节点
Entry<K,V> right = null; //右孩子节点
Entry<K,V> parent; //父节点
boolean color = BLACK; //节点的颜色,在红黑树种,只有两种颜色,红色和黑色 //构造方法,用指定的key,value ,parent初始化,color默认为黑色
Entry(K key, V value, Entry<K,V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
} //返回key
public K getKey() {
return key;
} //返回该节点对应的value
public V getValue() {
return value;
} //替换节点的值,并返回旧值
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
//重写equals()方法
public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
//两个节点的key相等,value相等,这两个节点才相等
return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
}
//重写hashCode()方法
public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
//key和vale hash值得异或运算,相同则为零,不同则为1
return keyHash ^ valueHash;
}
//重写toString()方法
public String toString() {
return key + "=" + value;
}
}

三,TreeMap源码阅读

  3.1 TreeMap的继承关系

    

   TreeMap实现了SotredMap接口,它是有序的集合。而且是一个红黑树结构,每个key-value都作为一个红黑树的节点。如果在调用TreeMap的构造函数时没有指定比较器,则根据key执行自然排序。

  3.2 TreeMap的成员变量

private final Comparator<? super K> comparator;  //比较器,是自然排序,还是定制排序 ,使用final修饰,表明一旦赋值便不允许改变
private transient Entry<K,V> root = null; //红黑树的根节点
private transient int size = 0; //TreeMap中存放的键值对的数量
private transient int modCount = 0; //修改的次数

  3.3 TreeMap的构造方法

//空参构造方法,comparator用键的顺序做比较
public TreeMap() {
comparator = null;
} //构造方法,提供比较器,用指定比较器排序
public TreeMap(Comparator<? super K> comparator) {
his.comparator = comparator;
} //将m中的元素转化daoTreeMap中,按照键的顺序做比较排序
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
} //构造方法,指定的参数为SortedMap
//采用m的比较器排序
public TreeMap(SortedMap<K, ? extends V> m) {
comparator = m.comparator();
try {
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}

  3.4 TreeMap的常用方法

public int size() {} // 返回个数

public boolean containsKey(Object key) {} // 是否包含某个key

public boolean containsValue(Object value) {} // 是否包含某个值

public V get(Object key) {} // 根据key取值 

public Comparator<? super K> comparator() {} // 排序的算法

public K firstKey() {} // 返回第一个key

public K lastKey() {} // 返回最后一个key

public void putAll(Map<? extends K, ? extends V> map) {} // 添加多个

public V put(K key, V value) {} // 添加一个

public V remove(Object key) {} // 删除

public void clear() {} // 清空

public Object clone() {} // 复制

public Map.Entry<K,V> firstEntry() {}

public Map.Entry<K,V> lastEntry() {}

public Map.Entry<K,V> pollFirstEntry() {}

public Map.Entry<K,V> pollLastEntry() {}

public Map.Entry<K,V> lowerEntry(K key) {}

public K lowerKey(K key) {}

public Map.Entry<K,V> floorEntry(K key) {}

public K floorKey(K key) {}

public Map.Entry<K,V> ceilingEntry(K key) {}

public K ceilingKey(K key) {}

public Map.Entry<K,V> higherEntry(K key) {}

public K higherKey(K key) {}

public Set<K> keySet() {}

public NavigableSet<K> navigableKeySet() {}

public NavigableSet<K> descendingKeySet() {}

public Collection<V> values() {}

public Set<Map.Entry<K,V>> entrySet() {}

public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive,K toKey,   boolean toInclusive) {}

public NavigableMap<K,V> headMap(K toKey, boolean inclusive) {}

public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) {}

public SortedMap<K,V> subMap(K fromKey, K toKey) {}

public SortedMap<K,V> headMap(K toKey) {}

public SortedMap<K,V> tailMap(K fromKey) {}

@Override
public boolean replace(K key, V oldValue, V newValue) {} // 对应值替换 @Override
public V replace(K key, V value) {} // 替换 @Override
public void forEach(BiConsumer<? super K, ? super V> action) {} // 提供便利 @Override
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {}

四,总结

  因为TreeMap是有序的,TreeMap的增删改查和统计相关的操作的时间复杂度都为 O(logn).相对于HashMap和LikedHashMap 这些 hash表的时间复杂度O(1)(不考虑冲突情况),TreeMap的增删改查的时间复杂度为O(logn)就显得效率较低。HashMap并不保证任何顺序性。LikedHashMap额外保证了Map的遍历顺序与put顺序一致的有序性。

JDK 1.8源码阅读 TreeMap的更多相关文章

  1. JDK 1.8 源码阅读和理解

    根据 一篇文章教会你,如何做到招聘要求中的“要有扎实的Java基础” 的指引,决定开始阅读下JDK源码. 本文将作为源码阅读总纲 一.精读部分 java.io java.lang java.util ...

  2. JDK 1.8源码阅读 HashMap

    一,前言 HashMap实现了Map的接口,而Map的类型是成对出现的.每个元素由键与值两部分组成,通过键可以找对所对应的值.Map中的集合不能包含重复的键,值可以重复:每个键只能对应一个值. 存储数 ...

  3. JDK 1.8源码阅读 HashSet

    一,前言 类实现Set接口,由哈希表支持(实际上是一个 HashMap集合).HashSet集合不能保证的迭代顺序与元素存储顺序相同.HashSet集合,采用哈希表结构存储数据,保证元素唯一性的方式依 ...

  4. JDK 1.8源码阅读 LinkList

    一,前言 LinkedList是一个实现了List接口和Deque接口的双端链表.有关索引的操作可能从链表头开始遍历到链表尾部,也可能从尾部遍历到链表头部,这取决于看索引更靠近哪一端. LinkedL ...

  5. JDK 1.8源码阅读 ArrayList

    一,前言 ArrayList是Java开发中使用比较频繁的一个类,通过对源码的解读,可以了解ArrayList的内部结构以及实现方法,清楚它的优缺点,以便我们在编程时灵活运用. 二,ArrayList ...

  6. 【JDK1.8】JDK1.8集合源码阅读——TreeMap(二)

    一.前言 在前一篇博客中,我们对TreeMap的继承关系进行了分析,在这一篇里,我们将分析TreeMap的数据结构,深入理解它的排序能力是如何实现的.这一节要有一定的数据结构基础,在阅读下面的之前,推 ...

  7. 【JDK1.8】JDK1.8集合源码阅读——TreeMap(一)

    一.前言 在前面两篇随笔中,我们提到过,当HashMap的桶过大的时候,会自动将链表转化成红黑树结构,当时一笔带过,因为我们将留在本章中,针对TreeMap进行详细的了解. 二.TreeMap的继承关 ...

  8. 【JDK】JDK源码分析-TreeMap(2)

    前文「JDK源码分析-TreeMap(1)」分析了 TreeMap 的一些方法,本文分析其中的增删方法.这也是红黑树插入和删除节点的操作,由于相对复杂,因此单独进行分析. 插入操作 该操作其实就是红黑 ...

  9. 【JDK1.8】Java 8源码阅读汇总

    一.前言 ​ 万丈高楼平地起,相信要想学好java,仅仅掌握基础的语法是远远不够的,从今天起,笔者将和园友们一起阅读jdk1.8的源码,并将阅读重点放在常见的诸如collection集合以及concu ...

随机推荐

  1. SQL自动流水号函数

    CREATE FUNCTION [dbo].[f_NextBH]() ) AS BEGIN ), ),),),) FROM Shop WITH(XLOCK,PAGLOCK)) END

  2. SQL Server 权限控制

    根据数据库Schema限制用户对数据库的操作行为 授予Shema dbo下对象的定义权限给某个用户(也就是说该用户可以修改架构dbo下所有表/视图/存储过程/函数的结构) use [Your DB N ...

  3. Java多线程系列——计数器 CountDownLatch

    简介: CountDownLatch 是一个非常实用的多线程控制工具类,通常用来控制线程的等待,它可以让某个线程等待直到倒计时结束 CountDownLatch 提供了两个主要的方法,await(). ...

  4. Qt学习记录--02 Qt的信号槽机制介绍(含Qt5与Qt4的差异对比)

    一 闲谈: 熟悉Window下编程的小伙伴们,对其消息机制并不陌生, 话说:一切皆消息.它可以很方便实现不同窗体之间的通信,然而MFC库将很多底层的消息都屏蔽了,尽管使用户更加方便.简易地处理消息,但 ...

  5. 利用final定义方法:这样的方法为一个不可覆盖的方法。

      常量(这里的常量指的是实例常量:即成员变量)赋值: ①在初始化的时候通过显式声明赋值.Final int x=3: ②在构造的时候赋值. 局部变量可以随时赋值.   利用final定义方法:这样的 ...

  6. postgresql某进程占用cpu资源过高,降不下来

    由于是开发阶段,所以并没有配置postgres的参数,都是使用安装时的默认配置,以前运行也不见得有什么不正常,可是前几天我的cpu资源占用突然升高.查看进程,发现有一个postgres的进程占用CPU ...

  7. DHT网络

    @(基础技术) 现在有一种方法,可以通过磁力链接,例如magnet:?xt=urn:btih:0482e0811014fd4cb5d207d08a7be616a4672daa,就可以获取BT文件. 这 ...

  8. Java API获取consumer group最新提交位移的时间

    碰到了有人问起这个问题,目前java consumer没有利用OffsetAndMetadata中的metadata字段记录提交的时间,故直接通过java consumer来查询是不行,我们需要直接读 ...

  9. Orders matters: seq2seq for set 实验

    论文提出了input的顺序影响seq2seq结果 有一些输入本身是无序的怎么去处理呢 作者提出LSTM controller的方式 替代输入的LSTM encode方式         作者实验这种方 ...

  10. go异常处理原则

    如果你定义的函数有可能失败,它就应该返回一个错误.当我调用其他package的函数时,如果这个函数实现的很好,我不需要担心它会panic,除非有真正的异常情况发生,即使那样也不应该是我去处理它.而pa ...