Java集合--TreeSet详细解析

目录

  • 1.构造函数
  • 2.增
  • 3.删
  • 4.比较器
  • 总结

谈到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()方法

原文地址:https://www.cnblogs.com/-1007813544/p/10780898.html

时间: 2024-10-11 23:06:34

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

Java - 集合框架完全解析

来自:http://www.jianshu.com/p/63e76826e852 数据结构是以某种形式将数据组织在一起的集合,它不仅存储数据,还支持访问和处理数据的操作.Java提供了几个能有效地组织和操作数据的数据结构,这些数据结构通常称为Java集合框架.在平常的学习开发中,灵活熟练地使用这些集合框架,可以很明显地提高我们的开发效率,当然仅仅会用还是不够的,理解其中的设计思想与原理才能更好地提高我们的开发水平.下面是自己对Java集合框架方面的学习总结. 一.概述 二.Collection接

java集合 源码解析 学习手册

学习路线: http://www.cnblogs.com/skywang12345/ 总结 1 总体框架 2 Collection架构 3 ArrayList详细介绍(源码解析)和使用示例 4 fail-fast总结(通过ArrayList来说明fail-fast的原理.解决办法) 5 LinkedList详细介绍(源码解析)和使用示例 6 Vector详细介绍(源码解析)和使用示例 7 Stack详细介绍(源码解析)和使用示例 8 List总结(LinkedList, ArrayList等使用

Java集合之List---ArrayList解析

本章节主要讲述ArrayList集合知识,主要包括ArrayList结构类型,集合特点,源码解析等. 欢迎持续关注阅读,一起学习,共同交流(477819525君羊). 1 ArrayList类层次结构: 2 ArrayList特性: a) ArrayList是基于数组实现的,是一个动态数组,可以动态的增加和减少元素,灵活的设置数组大小. b) ArrayList不是线程安全的,只能用在单线程环境下,多线程环境下可以考虑用Collections.synchronizedList(List l)函数

java集合数据的解析

java数据类型包括基本数据类型,引用数据类型和集合数据类型,那么他们各自都有什么作用,即为什么要用这么多数据类型? 对于数据的使用,其实,1.申明 2.初始化(静态初始化和动态初始化(即创建实例的过程))3.就是如何利用定义的数据(存取等操作) 基本数据类型,是针对单个数据类型的定义,比如,Int a=2;说明a是一个整型的数据,这单单只是一个数据. 那么如果要同时定义多个具有相同类型的数据呢?这里引出了数组int[] a={1,2,3,4,4};,而数组唯一的标识就是下标,而且最重要得一点是

玩转Java框架之详细解析

A 代码生成器(开发利器);     增删改查的处理类,service层,mybatis的xml,SQL( mysql   和oracle)脚本,   jsp页面 都生成   就不用写搬砖的代码了,生成的放到项目里,可以直接运行B 阿里巴巴数据库连接池druid;  数据库连接池  阿里巴巴的 druid.Druid在监控.可扩展性.稳定性和性能方面都有明显的优势C 安全权限框架shiro ;  Shiro 是一个用 Java 语言实现的框架,通过一个简单易用的 API 提供身份验证和授权,更安

【Java集合的详细研究9】Java堆栈(stack)的使用方法

栈是一种常用的数据结构,栈只允许访问栈顶的元素,栈就像一个杯子,每次都只能取杯子顶上的东西,而对于栈就只能每次访问它的栈顶元素,从而可以达到保护栈顶元素以下的其他元素."先进后出"或"后进先出"就是栈的一大特点,先进栈的元素总是要等到后进栈的元素出栈以后才能出栈.递归就是利用到了系统栈,暂时保存临时结果,对临时结果进行保护. 栈是存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中.

Java 集合系列17之 TreeSet详细介绍(源码解析)和使用示例

概要 这一章,我们对TreeSet进行学习.我们先对TreeSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeSet.内容包括:第1部分 TreeSet介绍第2部分 TreeSet数据结构第3部分 TreeSet源码解析(基于JDK1.6.0_45)第4部分 TreeSet遍历方式第5部分 TreeSet示例 转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3311268 第1部

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 概要  和学习ArrayList一样,接下来呢,我们先对LinkedList有个整体认识,然后再学习它的源码:最后再通过实例来学会使用LinkedList.内容包括:第1部分 LinkedList介绍第2部分 LinkedList数

Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 概要 上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解ArrayList.先对ArrayLis