谈到TreeSet的特点,估计大家脑海里想到的都是:有序,不可重复,红黑树,基于Treemap实现,自定义排序等特点。这篇博客帮助大家从源码梳理下TreeSet的知识点。

1.构造函数

TreeSet提供了四种构造器

  • TreeSet()
  • TreeSet(Collection< ? extends E> c)
  • TreeSet(Comparator< ? super E> comparator)
  • TreeSet(SortedSet< E > s)

四种构造器在底层都调用了同一个方法。以无参构造函数为例。[1]处的this方法最终调用的是[2]的方法,其中四个构造器的传参都被TreeMap封装了一层。

   public TreeSet() {
this(new TreeMap<E,Object>()); //[1]
}
TreeSet(NavigableMap<E,Object> m) {//[2]
this.m = m;
}

2.增

TreeSet在添加元素时,会把元素放入TreeMap中的key上来确保元素的唯一性,并让其value指向一个空对象。TreeSet#add()方法会调用TreeMap#put()方法添加元素,添加元素时,从树的根节点开始遍历直到找到新增元素的parent节点,添加进去。通过TreeMap的源码可以看出维护的是一个红黑树数据结构。

PS:由于TreeSet的实例化时都会调用TreeMap的无参构造函数,此时

TreeMap#comparator=null;

   private static final Object PRESENT = new Object();

   public boolean add(E e) {
return m.put(e, PRESENT)==null;
} public boolean addAll(Collection<? extends E> c) {
// Use linear-time version if applicable
if (m.size()==0 && c.size() > 0 &&
c instanceof SortedSet && //是否是SortedSet类或其子类
m instanceof TreeMap) {
SortedSet<? extends E> set = (SortedSet<? extends E>) c;
TreeMap<E,Object> map = (TreeMap<E, Object>) m;
Comparator<?> cc = set.comparator();
Comparator<? super E> mc = map.comparator();
if (cc==mc || (cc != null && cc.equals(mc))) {//[3]
map.addAllForTreeSet(set, PRESENT);
return true;
}
}
return super.addAll(c); // 不是SortedSet子类,就是Collection子类
}

3.删

TreeSet中提供了两个和删除相关的方法。

TreeSet#clear()复用了TreeMap#clear()方法,把root节点置为null,size置为0;

通过TreeSet#remove()移除特定元素时,TreeSet首先先遍历出该元素,然后将红黑树中的元素置为null,重新平衡红黑树。

   public boolean remove(Object o) {
return m.remove(o)==PRESENT;
} public void clear() {
m.clear();
} /**
* Delete node p, and then rebalance the tree.
*/
private void deleteEntry(Entry<K,V> p) {
modCount++;
size--;
// If strictly internal, copy successor's element to p and then make p
// point to successor.
if (p.left != null && p.right != null) {
Entry<K,V> s = successor(p);
p.key = s.key;
p.value = s.value;
p = s;
} // p has 2 children // Start fixup at replacement node, if it exists.
Entry<K,V> replacement = (p.left != null ? p.left : p.right); if (replacement != null) {
// Link replacement to parent
replacement.parent = p.parent;
if (p.parent == null)
root = replacement;
else if (p == p.parent.left)
p.parent.left = replacement;
else
p.parent.right = replacement; // Null out links so they are OK to use by fixAfterDeletion.
p.left = p.right = p.parent = null; // Fix replacement
if (p.color == BLACK)
fixAfterDeletion(replacement);
} else if (p.parent == null) { // return if we are the only node.
root = null;
} else { // No children. Use self as phantom replacement and unlink.
if (p.color == BLACK)
fixAfterDeletion(p); if (p.parent != null) {
if (p == p.parent.left)
p.parent.left = null;
else if (p == p.parent.right)
p.parent.right = null;
p.parent = null;
}
}
}

4.比较器

TreeSet中有两种排序,一个是自然排序,一个是重写compareTo()方法自定义排序。

自然排序可以参考Integer,String等类中的实现。其顺序也是我们常见的“1,2,3,4”,“a,b,c,d”。假如我们想让Student对象中String类型的字段倒序输出呢

@Data
public class Student implements Comparable<Student>{
String name;
/**
* 这里的参数o,其实是TreeMap中维护的根节点
* @param o
* @return
*/
@Override
public int compareTo(Student o) {
System.out.println("name:"+name+",参数:"+o.getName());
int i = this.name.compareTo(o.getName());
return i==0?0:-i;
}
} public static void main(String[] args) {
Set<Student> set = new TreeSet<>();
Student a = new Student();
a.setName("a");
Student b = new Student();
b.setName("b");
Student c = new Student();
c.setName("c");
Student d = new Student();
d.setName("d");
Student e = new Student();
e.setName("e");
Student f = new Student();
f.setName("f");
set.add(a);
set.add(c);
set.add(e);
set.add(b);
set.add(d);
set.add(f);
for (Student str: set) {
System.out.print(str.getName());
}
}

其结果如下:



从打印的日志可以看出,每次插入新的元素,都会从根节点开始遍历比较。当然TreeSet中也提供了我们倒序输出的方法。有兴趣可以自己试验下。

  • descendingSet()
  • descendingIterator()

总结

TreeSet是通过TreeMap实现的一个有序的、不可重复的集合,底层维护的是红黑树结构。当TreeSet的泛型对象不是java的基本类型的包装类时,对象需要重写Comparable#compareTo()方法

Java集合--TreeSet详细解析的更多相关文章

  1. [转]Java - 集合框架完全解析

    数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.Java提供了几个能有效地组织和操作数据的数据结构,这些数据结构通常称为Java集合框架.在平常的学习开发中,灵 ...

  2. Java集合--TreeSet

    转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3311268 第1部分 TreeSet介绍 TreeS ...

  3. Java - 集合框架完全解析

    来自:http://www.jianshu.com/p/63e76826e852 数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.Java提供了几个能有效地组织 ...

  4. Java集合框架详细总结

    一:Collection集合 呼~,历过好几天的奋战终于把集合框架肝完了,b站某马老师讲的是真的非常详细而且动听,原理给你分析得明明白白的,此前也找了许多关于集合这一大章节的视频,发现更多的是针对于使 ...

  5. java集合 源码解析 学习手册

    学习路线: http://www.cnblogs.com/skywang12345/ 总结 1 总体框架 2 Collection架构 3 ArrayList详细介绍(源码解析)和使用示例 4 fai ...

  6. Java 集合基础详细介绍

    一.Java集合框架概述 集合.数组都是对多个数据进行存储操作的结构,简称Java容器.此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt, .jpg, .avi,数据库中).Jav ...

  7. Java集合最全解析,学集合,看这篇就够用了!!!

    在看集合类之前, 我们要先明白一下概念: 1.数据结构 (1):线性表 [1]:顺序存储结构(也叫顺序表) 一个线性表是n个具有相同特性的数据元素的有限序列.数据元素是一个抽象的符号,其具体含义在不同 ...

  8. Java 集合源码解析(2):ListIterator

    点击查看 Java 集合框架深入理解 系列, - ( ゜- ゜)つロ 乾杯~ 今天心情和股票一样红,还是学学 ListIterator 吧! ListIterator 根据官方文档介绍, ListIt ...

  9. Java 集合源码解析(1):Iterator

    Java, Android 开发也有段时间了,当初为了早点学 Android,Java 匆匆了解个大概就结束了,基础不够扎实. 虽然集合框架经常用,但是一直没有仔细看看原理,仅止于会用,不知道为什么要 ...

随机推荐

  1. linux 系统centOS 7 怎么在线安装mysql

    以下操作,注意空格,为避免出错,可以选择直接copy 第一步: 输入命令行      yum list installed | grep mysql       检查是否已经安装mysql 已安装输入 ...

  2. html5 下拉刷新(pc+移动网页源码)

    本文demo下载地址:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=1071 本文实现在html5网页中使用下 ...

  3. 利用arcserver 自带tomcat实现上传shapefile、cad等文件,然后用soe解析。

    一.功能实现分析 1.soe中传入指定路径目录和文件名就能读取shp.cad并解析,然后返回JSON格式数据给flex端生成图形.(soe读取的是本地绝对路径) 2.所以首先要上传文件到soe发布所在 ...

  4. 网络传输数据封装详解(IP,UDP,TCP)

    IP数据包也叫IP报文分组,传输在ISO网络7层结构中的网络层,它由IP报文头和IP报文用户数据组成,IP报文头的长度一般在20到60个字节之间,而一个IP分组的最大长度则不能超过65535个字节.  ...

  5. ADC0832的应用

    ADC0832是美国国家半导体公司生产的一种8位逐次比较型CMOS双通道A-D转换器,采用5V电源电压供电,模拟电压输入范围为0~5V,内部时钟250KHz时转换速度为32微秒. 仿真图为: 程序为: ...

  6. HTML结构及基础语法

    一.HTML结构 <!DOCTYPE html><html lang="en"><head> <meta charset="UT ...

  7. LR测试

    LoadRunner种预测系统行性能负载测试工具通模拟千万用户实施并发负载及实性能监测式确认查找问题LoadRunner能够整企业架构进行测试通使用 LoadRunner企业能限度缩短测试间优化性能加 ...

  8. redis Web服务器

    redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...

  9. HTTP多线程下载+断点续传(libcurl库)

    目录索引: 一.LibCurl基本编程框架 二.一些基本的函数 三.curl_easy_setopt函数部分选项介绍 四.curl_easy_perform 函数说明(error 状态码) 五.lib ...

  10. .Net Core微服务系列--理论篇

    微服务的由来 微服务最早由Martin Fowler与James Lewis于2014年共同提出来的,但是微服务也不是一个全新的概念,它是由一系列在实践中获得成功并流行起来的概念中总结出来的一种模式, ...