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. 初探中间件(middleware)

    初探中间件(middleware) 因为考虑到文章的长度, 所以 BaseHandler 的展开被推迟了. 在 BaseHandler 中隐藏着中间件的信息, 较常见的 SessionMiddlewa ...

  2. Redis系统学习 二、数据结构

    一.字符串     1.在Redis里,字符串是最基本的数据结构.当你在思索着关键字-值对时,你就是在死锁着字符串数据结构.不要被名字给搞混了. 常见实例: set users:leto " ...

  3. WCF学习笔记之传输安全

    WCF学习笔记之传输安全 最近学习[WCF全面解析]下册的知识,针对传输安全的内容做一个简单的记录,这边只是简单的记录一些要点:本文的内容均来自[WCF全面解析]下册: WCF的传输安全主要涉及认证. ...

  4. offsetWidth, offsetHeight, offsetLeft, offsetTop,clientWidth, clientHeight,clientX,pageX,screenX

    offsetWidth: 元素在水平方向上占用的空间大小.包括元素的宽度,内边距,(可见的)垂直滚动条的宽度,左右边框的宽度. offsetHeight:元素在垂直方向上占用的空间大小,包括元素的高度 ...

  5. JBoss + EJB3 + MySql : 开发第一个EJB

    JBoss开发Bean并不困难,而对于不知道的人来说,数据库配置才是比较棘手的问题.现在我们就来一步一步开发一个EJB3 + MySql的Bean. 一.MySql数据库的配置 1. 配置数据源 在 ...

  6. Android本地化资源目录详解

    我们可以设想,有两个不同分辨率的手机(320*480和480*800)要使用一些图像资源,为了使图像不失真,就需要为不同分辨率的手机指定不同的图像,为此就需要建立不同的资源目录. 在res目录中建立了 ...

  7. HTTP协议系列(2)--顺带离职的一些想法

    一.聊聊离职感悟      来杭州也是将近3个月了,也迎来我的第一次辞职,有可能你会说我傻怎么不拿年终奖,也有可能你会不理解为什么3个月就要辞职:我只能说我是怀揣的梦想来的,我想着进一步的提升,想着成 ...

  8. AngularJS2之Angular正式初探

    前言:angular的官方教程真的不错.强烈推荐!!!] 按照环境搭建教程新建一个项目: 项目的结构如下: 其中package.json指示node需要安装的插件(npm install指令会安装的插 ...

  9. PostgreSQL学习手册(常用数据类型)

    一.数值类型:     下面是PostgreSQL所支持的数值类型的列表和简单说明: 名字 存储空间 描述 范围 smallint 2 字节 小范围整数 -32768 到 +32767 integer ...

  10. 关于intelliJ idea创建servlet提示cannot resolve symbol‘servlet’的问题

    在刚刚折腾idea的时候会出现一系列的问题,就比如创建Servlet的时候,编辑器提示cannot resolve symbol'servlet'.出现这样的问题是因为在第一次用idea的时候还没有配 ...