TreeSet与TreeMap的源码分析 JDK7
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的更多相关文章
- TreeSet实现原理及源码分析
类似于HashMap和HashSet之间的关系,HashSet底层依赖于HashMap实现,TreeSet底层则采用一个NavigableMap来保存TreeSet集合的元素.但实际上,由于Navig ...
- HashMap与TreeMap源码分析
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
- Java集合源码分析(六)TreeSet<E>
TreeSet简介 TreeSet 是一个有序的集合,它的作用是提供有序的Set集合.它继承于AbstractSet抽象类,实现了NavigableSet<E>, Cloneable, j ...
- 死磕 java集合之TreeSet源码分析
问题 (1)TreeSet真的是使用TreeMap来存储元素的吗? (2)TreeSet是有序的吗? (3)TreeSet和LinkedHashSet有何不同? 简介 TreeSet底层是采用Tree ...
- 集合之TreeSet(含JDK1.8源码分析)
一.前言 前面分析了Set接口下的hashSet和linkedHashSet,下面接着来看treeSet,treeSet的底层实现是基于treeMap的. 四个关注点在treeSet上的答案 二.tr ...
- Java集合源码分析(十)——TreeSet
简介 TreeSet就是一个集合,里面不能有重复的元素,但是元素是有序的. TreeSet其实就是调用了TreeMap实现的,所以,它也不是线程安全的.可以实现自然排序或者根据传入的Comparato ...
- 【集合框架】JDK1.8源码分析之TreeMap(五)
一.前言 当我们需要把插入的元素进行排序的时候,就是时候考虑TreeMap了,从名字上来看,TreeMap肯定是和树是脱不了干系的,它是一个排序了的Map,下面我们来着重分析其源码,理解其底层如何实现 ...
- TreeMap 源码分析
简介 TreeMap最早出现在JDK 1.2中,是 Java 集合框架中比较重要一个的实现.TreeMap 底层基于红黑树实现,可保证在log(n)时间复杂度内完成 containsKey.get.p ...
- 集合之TreeMap(含JDK1.8源码分析)
一.前言 前面所说的hashMap和linkedHashMap都不具备统计的功能,或者说它们的统计性能的时间复杂度都不是很好,要想对两者进行统计,需要遍历所有的entry,时间复杂度比较高,此时,我们 ...
随机推荐
- js在IE浏览器和非IE浏览器中的兼容性问题
下面列出IE和非IE中常见的一些js兼容性问题. //window.event IE:有window.event对象 非IE:没有window.event对象.可以通过给函数的参数传递eve ...
- C#操作AD及Exchange Server总结
C#操作AD及Exchange Server总结 这篇博客的目的:根据亲身项目经历,总结对AD及Exchange Server的操作,包括新建AD用户,设置密码,为AD用户创建邮箱等. 本文完全原创, ...
- enode框架step by step之事件驱动架构(EDA)思想的在框架中如何体现
enode框架step by step之事件驱动架构(EDA)思想的在框架中如何体现 上一篇文章,我给大家分享了我的一个基于DDD以及EDA架构的框架enode,但是只是介绍了一个大概.接下来我准备用 ...
- c# AutoResetEvent和ManualResetEvent
网上有很多AutoResetEvent和ManualResetEvent的详细介绍,在这里不做过多详细的解释,写下自己的一点心得留作备忘. AutoResetEvent和ManualResetEven ...
- 深入浅出Redis-redis底层数据结构(下)
概述: 学习使用Redis,其实并不需要去研究其底层数据的实现.我们只需要了解他有哪些常用的数据类型,然后熟练使用,就可以很好的掌握Redis 这个工具了.但是这样的学习方法只适合Redis 的入门, ...
- php最新学习-----文件的操作
一.文件:文件和目录 (1)判断文件的类型用:filetype() filetype("文件路径+文件名") //判断文件的类型 例如:我这里查找的的上一级目录中的json文件,输 ...
- 使用多个DNS供应商以缓解DDoS攻击
随着不安全物联网(IoT)设备的激增,针对域名系统(DNS)供应商的分布式拒绝服务(DDoS)攻击在数量和规模上正在不断增加.这些攻击随之影响依赖于这些供应商进行域名解析的网站.虽然DNS供应 ...
- elike.python.function()
将python用于基本的科学计算,能完全替代matlab.就最近写的一个物理模型程序来看,用python建立的物理模型的可控性,代码的层次性都优于matlab,只不过python没有matlab那样的 ...
- 【JS学习笔记】函数传参
比如仅仅改变背景的颜色 函数传参:参数就是占位符. 那么在什么时候用传参呢?函数里定不下来的东西. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1 ...
- oracle if else 判断
CREATE OR REPLACE FUNCTION fn_GetClassifyBymxmjazfs (v_azfs varchar2,v_mx varchar2,v_mj varchar2) re ...