TreeSet存储原则是:不可重复,有序的。

public TreeSet() {
this(new TreeMap<E,Object>());
}
    public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}

上面是TreeSet常用的两个构造函数。

底层实现也就是TreeMap。

 TreeSet(NavigableMap<E,Object> m) {
this.m = m;
}
    /**
* The backing map.
*/
private transient NavigableMap<E,Object> m; // Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

维护了上面两个变量。

add方法

public boolean add(E e) {
return m.put(e, PRESENT)==null;
}

因为TreeMap存储的是键值对,因此他将要保存的元素作为key,以一个常量作为值保存到TreeMap中。

这就是为什么TreeSet保存的元素是不可重复的了,因为TreeMap的键不可以重复。

到这里TreeSet也差不多分析完了,主要还是分析TreeMap,因为实现在他里面。

TreeMap常用构造函数:

    public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
    public TreeMap() {
comparator = null;
}

这里Comparator是一个比较器,这就是为什么TreeSet是有序的原因了。

    private final Comparator<? super K> comparator;

    private transient Entry<K,V> root = null;

上面两个主要变量,一个是比较器,一个是根。这个根是因为数据结构而设计的,一种红黑树或者叫二叉树的一种数据结构。TreeMap也是根据这个数据结构而设计的。

好,我们来看看添加元素的真面目吧。

public V put(K key, V value) {
Entry<K,V> t = root;//得到根节点
if (t == null) {//添加第一个元素
compare(key, key); // type (and possibly null) check root = new Entry<>(key, value, null);//根节点就是第一个添加进来的元素,前一个节点为null
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {//有比较器
do {
parent = t;//从根节点出发
cmp = cpr.compare(key, t.key);//新添加进来的元素和根节点比较
if (cmp < 0)//小了,放左边
t = t.left;
else if (cmp > 0)//大了,放右边
t = t.right;
else
return t.setValue(value);//相等直接返回,且将新的元素值替换掉旧的
} while (t != null);//直到没有左右节点
}
else {
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);//根据自然排序
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;//此时,parent元素的值最小,新元素的值比parent还小,放在parent左边
else
parent.right = e;//此时,parent元素的值最最大,新元素的值比parent还大,放在parent右边
fixAfterInsertion(e);
size++;
modCount++;
return null;
}

好,现在元素放进去了,要取出来吧。使用iterator()方法。

//TreeSet
public Iterator<E> iterator() {
return m.navigableKeySet().iterator();
}

TreeSet的iterator方法是调用了TreeMap的方法。这个方法是从JDK1.6开始有的

 /**
* @since 1.6
*/
public NavigableSet<K> navigableKeySet() {
KeySet<K> nks = navigableKeySet;
return (nks != null) ? nks : (navigableKeySet = new KeySet(this));
}

实际上就是调用了KeySet的iterator方法。

TreeSet与TreeMap的源码分析 JDK7的更多相关文章

  1. TreeSet实现原理及源码分析

    类似于HashMap和HashSet之间的关系,HashSet底层依赖于HashMap实现,TreeSet底层则采用一个NavigableMap来保存TreeSet集合的元素.但实际上,由于Navig ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. Java集合源码分析(六)TreeSet<E>

    TreeSet简介 TreeSet 是一个有序的集合,它的作用是提供有序的Set集合.它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, j ...

  4. 死磕 java集合之TreeSet源码分析

    问题 (1)TreeSet真的是使用TreeMap来存储元素的吗? (2)TreeSet是有序的吗? (3)TreeSet和LinkedHashSet有何不同? 简介 TreeSet底层是采用Tree ...

  5. 集合之TreeSet(含JDK1.8源码分析)

    一.前言 前面分析了Set接口下的hashSet和linkedHashSet,下面接着来看treeSet,treeSet的底层实现是基于treeMap的. 四个关注点在treeSet上的答案 二.tr ...

  6. Java集合源码分析(十)——TreeSet

    简介 TreeSet就是一个集合,里面不能有重复的元素,但是元素是有序的. TreeSet其实就是调用了TreeMap实现的,所以,它也不是线程安全的.可以实现自然排序或者根据传入的Comparato ...

  7. 【集合框架】JDK1.8源码分析之TreeMap(五)

    一.前言 当我们需要把插入的元素进行排序的时候,就是时候考虑TreeMap了,从名字上来看,TreeMap肯定是和树是脱不了干系的,它是一个排序了的Map,下面我们来着重分析其源码,理解其底层如何实现 ...

  8. TreeMap 源码分析

    简介 TreeMap最早出现在JDK 1.2中,是 Java 集合框架中比较重要一个的实现.TreeMap 底层基于红黑树实现,可保证在log(n)时间复杂度内完成 containsKey.get.p ...

  9. 集合之TreeMap(含JDK1.8源码分析)

    一.前言 前面所说的hashMap和linkedHashMap都不具备统计的功能,或者说它们的统计性能的时间复杂度都不是很好,要想对两者进行统计,需要遍历所有的entry,时间复杂度比较高,此时,我们 ...

随机推荐

  1. Devexpress XtraReports 交叉报表

    [原创]Devexpress XtraReports 系列 5 创建交叉报表   昨天我们已经介绍了如何创建多栏报表,详见:[原创]Devexpress XtraReports 系列 4 创建多栏报表 ...

  2. 整合MVVM框架(Prism)

    整合MVVM框架(Prism) 我们基础的框架已经搭建起来了,现在整合MVVM框架Prism,在ViewModel做一些逻辑处理,真正把界面设计分离出来. 这样方便我们系统开发分工合作,同时提高系统可 ...

  3. 简单使用JSON,JavaScript读取JSON文本(三)

    JavaScript 读取 JSON 文本转换为对象 JSON 最常见的用法之一,是从 web 服务器上读取 JSON 数据(作为文件或作为 HttpRequest),将 JSON 数据转换为 Jav ...

  4. 什么时候用spring

    论公司spring的滥用   这个公司每个项目用不同的一套开发框架,实在忍不住拿一个出来说说事.

  5. 不想作死系列---virtualbox最小化安装centos6.5

    背景: 最近已经重装了5个系统,实在不想折腾了.于是打算在虚拟机中安装所需环境. 系统版本: 宿主机:win7 virtualbox4.3.10 centos 6.5(final) 1.下载安装vir ...

  6. Android call setting 源码分析 (上)

    Android 的 call setting 是用来设定与 simcard 相关的一些内容的应用程序,如网络,PIN等等,算是AP层.这里就选择其中一个项从源代码读下去直到底层,看看大概的结构和流程. ...

  7. 配置 Ionic环境

    本博客只适合win7 系统 准备  必须要有 注意了!!!! //注意所以路径均不支持中文 1.安装JSK (jsva环境) 默认安装位置 如果是32位操作系统  需要安装32bit版的JDK C:\ ...

  8. 【C语言】一些重要的知识点

    1.#include <stdio.h> #include 是C语言的预处理指令之一,所谓预处理,就是在编译之前做的处理,预处理指令一般以 # 开头 #include 指令后面会跟着一个文 ...

  9. 结构-行为-样式-angularJs 指令实现滚动文字

    最近在做XX项目的大屏展示页面,有一个表格需要用到这个滚动效果,于是就写了个指令,记录下,共同学习. Html代码: <td word-roll tword="item"&g ...

  10. Javascript设计模式之装饰者模式详解篇

    一.前言: 装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象. 装饰者模式的特点: 1. 在不改 ...