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. java中除去字符串(String)中的换行字符(\r \n)

    有时在文本框中输入内容特别是粘贴内容时会出现一些换行符(\r\n),如下,在做字数验证或保存到数据库中时应过滤掉. str.replaceAll("\r|\n","&qu ...

  2. 大数据应用日志采集之Scribe 安装配置指南

    大数据应用日志采集之Scribe 安装配置指南 大数据应用日志采集之Scribe 安装配置指南 1.概述 Scribe是Facebook开源的日志收集系统,在Facebook内部已经得到大量的应用.它 ...

  3. 一步步学习Python-django开发-Mac下搭建Python-Django环境

    首先确定学习那一个版本,以之前对Python的接触,Python2.x 的版本仍然占据很大的市场.但作为初学者我还是决定学习新的版本,相信未来会逐渐转向3.x版本的. 其实搭建Python不是一件很难 ...

  4. hdu 1213 How Many Tables(并查集练习)

    题目链接:hdu1213 赤裸裸的并查集.....水题一个.... #include<stdio.h> #include<string.h> #include<algor ...

  5. Oracle体系结构及备份(十七)——bg-others

    一 其他进程 Archiver (ARCn) Oneor more archiver processes copy the redo log files to archival storage whe ...

  6. 在egret中使用protobuf

    原文章删除,重新使用MarkDown排版 在H5游戏领域,对于服务端与客户端的通信协议有一个选择,那就是使用protobuf.js.对于那些直接使用JavaScript开发的引擎而言,protobuf ...

  7. 通过python为zabbix发送告警邮件

    最近部署ZABBIX的邮件告警时,用刚学的python来写告警邮件脚本. 由于时间有限,我只对关键步骤做截图,对zabbix的基本配置略过. python代码如下 1 #!/usr/bin/pytho ...

  8. SharePoint Framework (SPFx)安装配置以及开发-基础篇

    前言 SharePoint Framework(SPFx),是页面 和Webpart的模型,完全支持本地开发(即完全可以脱离SharPoint环境在本地进行开发),SPFx包含了一系列的client- ...

  9. window7环境下VMWare自定义安装Linux虚拟机完全教程

    1.首先准备好以下工具和安装包,最好到官网下载: VMWare 8.x,注意版本不易过高,因为很多时候会出现和Linux镜像不兼容的情况,下载地址:http://www.vmware.com/cn.h ...

  10. Windows设置VMware开机自动启动,虚拟机也启动

    很多用windows系统电脑开发的童鞋,会在自己电脑上装一个虚拟机,然后在装一个linux系统当作服务器来使用.但每次电脑开机都要去重启一下虚拟机电源,实在是不划算.下面博主教大家在windows系统 ...