谈到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. Oracle入门《Oracle介绍》第一章1-3 Oracle 逻辑组件

    一.数据库的逻辑结构是从逻辑的角度分析数据库的组成.Oracle 的逻辑组件包括: 1.表空间 表空间是数据库中最大的逻辑单位,一个 Oracle 数据库至少包含一个表空间,就是名为SYSTEM的系统 ...

  2. Spring Boot实战笔记(四)-- Spring常用配置(事件Application Event)

    一.事件(Application Event) Spring的事件为Bean和Bean之间的消息通信提供了支持.当一个Bean处理完一个任务之后,希望另一个Bean知道并能做相应的处理,这时我们就需要 ...

  3. cas 4.1.4单点登录实战

    使用工具 maven-3.3.9 cas-4.1.4 Tomcat-7.0.57-win-x64 cas-sample-Java-webapp 一.Hello cas 1.下载Tomcat,解压:修改 ...

  4. javascript 正则(将数字转化为三位分隔的样式)

    '12345678912345678'.replace(/\B(?=(?:\d{3})+\b)/g, ',') 解释: \b : 匹配单词边界,就是位于字符\w([a-zA-Z0-9_])和\W[^a ...

  5. 关于内核转储(core dump)的设置方法

    原作者:http://blog.csdn.net/wj_j2ee/article/details/7161586 1. 内核转储作用 (1) 内核转储的最大好处是能够保存问题发生时的状态. (2) 只 ...

  6. resteasy上传文件写法

    resteasy服务器代码 @Path(value = "file") public class UploadFileService { private final String ...

  7. 架构选型之Nodejs与Java

    前言: 身边越来越多的同事谈论Nodejs,谈其异步IO.事件回调.前后台统一一门语言,创业的朋友的第一个创业项目也选择了Nodejs,期望能够使用一种语言节省成本快速完成需求开发.与其他项目组的同事 ...

  8. PHP设计模式 -- 注册模式

    参考文章:https://segmentfault.com/a/1190000007495855 简介 注册树模式又称注册模式或注册器模式.注册树模式通过将对象实例注册到一棵全局的对象树上,需要的时候 ...

  9. Sublime Text 3 Build 3065 License key 注册码 秘钥

    -– BEGIN LICENSE -– Andrew Weber Single User License EA7E-855605 813A03DD 5E4AD9E6 6C0EEB94 BC99798F ...

  10. (二)Servlet入门之HelloWorld

    在整个Servlet程序中最重要的就是Servlet接口,在此接口下定义了一个GenericServlet的子类,但是,一般不会直接继承此类,而是根据所使用的协议选择GenericServlet的子类 ...