java source code - TreeSet

  In fact, this TreeSet and HashSet similar. Underlying HashSet is implemented by HashMap, TreeSet underlying fact is implemented by TreeMap.

Brief introduction

  Role TreeSet is stored without duplication of data, but also data sorted.

  TreeMap bottom is realized by a red-black tree, so TreeSet underlayer is achieved by a red-black tree.

  TreeSet most important characteristic is the elements sorted. We summarize its characteristics:

    (1) TreeSet is a TreeMap NavigableSet implementation.

    (2) TreeSet elements stored in the key in the TreeMap, TreeMap the value is a constant object.

    (3) non-thread-safe.

    (4) java8 new splitter spliterator () method.

Source code analysis

1. inheritance

    

 

 

 2. Variable parameters

    

 

 

 3. Constructor

 // directly passed in the storage element NavigableMap
     // this is not a deep copy, if an element added onto the outside of the map will be reflected here
     // Further, this method is not public, it can only be described to the same packet using 
    TreeSet (NavigableMap < E, Object> m) {
         the this .m = m; 
    } 

    // use TreeMap initialization 
    public TreeSet () {
         the this ( new new TreeMap <E, Object> ()); 
    } 

    // used with the comparator initialization TreeMap 
    public TreeSet (Comparator <? Super E> Comparator) {
         the this ( new new the TreeMap <> (Comparator)); 
    } 

    //Adding all the elements of the set of c, a TreeSet 
    public TreeSet (Collection <? The extends E> c) {
         the this (); 
        the addAll (c); 
    } 

    // Add all the elements into a TreeSet SortedSet in 
    public TreeSet (SortedSet < E> S) {
         the this (s.comparator ()); 
        the addAll (S); 
    }

4 Methods

 // 迭代器
    public Iterator<E> iterator() {
        return m.navigableKeySet().iterator();
    }

    // 逆序迭代器
    public Iterator<E> descendingIterator() {
        return m.descendingKeySet().iterator();
    }

    // 以逆序返回一个新的TreeSet
    public NavigableSet<E> descendingSet() {
        return new TreeSet<>(m.descendingMap());
    }

    // 元素个数
    public int size() {
        return m.size();
    }

    // 判断是否为空【本篇文章由公众号“彤哥读源码”原创】
    public boolean isEmpty() {
        return m.isEmpty();
    }

    // 判断是否包含某元素
    public boolean contains(Object o) {
        return m.containsKey(o);
    }

    // 添加元素, 调用map的put()方法, value为PRESENT
    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }
    
    // 删除元素
    public boolean remove(Object o) {
        return m.remove(o)==PRESENT;
    }

    // 清空所有元素
    public void clear() {
        m.clear();
    }

    // 添加集合c中的所有元素
    public  boolean addAll(Collection<? extends E> c) {
        // 满足一定条件时直接调用TreeMap的addAllForTreeSet()方法添加元素
        if (m.size()==0 && c.size() > 0 &&
            c instanceof 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))) {
                map.addAllForTreeSet(set, PRESENT);
                return true;
            }
        }
        // 不满足上述条件, 调用父类的addAll()通过遍历的方式一个一个地添加元素
        return super.addAll(c);
    }

    // 子set(NavigableSet中的方法)
    public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                                  E toElement,   boolean toInclusive) {
        return new TreeSet<>(m.subMap(fromElement, fromInclusive,
                                       toElement,   toInclusive));
    }
    
    // 头set(NavigableSet中的方法)
    public NavigableSet<E> headSet(E toElement, boolean inclusive) {
        return new TreeSet<>(m.headMap(toElement, inclusive));
    }

    // 尾set(NavigableSet中的方法)
    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) {
        return new TreeSet<>(m.tailMap(fromElement, inclusive));
    }

    // 子set(SortedSet接口中的方法)
    public SortedSet<E> subSet(E fromElement, E toElement) {
        return subSet(fromElement, true, toElement, false);
    }

    // 头set(SortedSet接口中的方法)
    public SortedSet<E> headSet(E toElement) {
        return headSet(toElement, false);
    }
    
    // 尾set(SortedSet接口中的方法)
    public SortedSet<E> tailSet(E fromElement) {
        return tailSet(fromElement, true);
    }

    // 比较器
    public Comparator<? super E> comparator() {
        return m.comparator();
    }

    // 返回最小的元素
    public E first() {
        return m.firstKey();
    }
    
    // 返回最大的元素
    public E last() {
        return m.lastKey();
    }

    // 返回小于e的最大的元素
    public E lower(E e) {
        return m.lowerKey(e);
    }

    // 返回小于等于e的最大的元素
    public E floor(E e) {
        return m.floorKey(e);
    }
    
    // 返回大于等于e的最小的元素
    public E ceiling(E e) {
        return m.ceilingKey(e);
    }
    
    // 返回大于e的最小的元素
    public E higher(E e) {
        return m.higherKey(e);
    }
    
    // 弹出第一个的元素,就是最小元素
    public E pollFirst() {
        Map.Entry<E,?> e = m.pollFirstEntry();
        return (e == null) ? null : e.getKey();
    }
  //弹出最后一个元素,就是最大元素
    public E pollLast() {
        Map.Entry<E,?> e = m.pollLastEntry();
        return (e == null) ? null : e.getKey();
    }

    // 克隆方法
    @SuppressWarnings("unchecked")
    public Object clone() {
        TreeSet<E> clone;
        try {
            clone = (TreeSet<E>) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new InternalError(e);
        }

        clone.m = new TreeMap<>(m);
        return clone;
    }

    // 序列化写出方法
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException {
        // Write out any hidden stuff
        s.defaultWriteObject();

        // Write out Comparator
        s.writeObject(m.comparator());

        // Write out size
        s.writeInt(m.size());

        // Write out all elements in the proper order.
        for (E e : m.keySet())
            s.writeObject(e);
    }

    // 序列化写入方法
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        // Read in any hidden stuff
        s.defaultReadObject();

        // Read in Comparator
        @SuppressWarnings("unchecked")
            Comparator<? super E> c = (Comparator<? super E>) s.readObject();

        // Create backing TreeMap
        TreeMap<E,Object> tm = new TreeMap<>(c);
        m = tm;

        // Read in size
        int size = s.readInt();

        tm.readTreeSet(size, s, PRESENT);
    }

    // 可分割的迭代器
    public Spliterator<E> spliterator() {
        return TreeMap.keySpliteratorFor(m);
    }

    // 序列化id
    private static final long serialVersionUID = -2479143000061671589L;

总结

(1)TreeSet底层使用NavigableMap存储元素;

(2)TreeSet是有序的【本篇文章由公众号“彤哥读源码”原创】;

(3)TreeSet是非线程安全的;

(4)TreeSet实现了NavigableSet接口,而NavigableSet继承自SortedSet接口;

(5)TreeSet实现了SortedSet接口;

彩蛋

(1)通过之前的学习,我们知道TreeSet和LinkedHashSet都是有序的,那它们有何不同?

  LinkedHashSet没有实现SortedSet接口,有序性主要依赖于LinkedHashMap的有序性,所以它的有序性是指按照插入顺序保证的有序性

       而TreeSet实现了SortedSet接口,它的有序性主要依赖于NavigableMap的有序性,而NavigableMap又继承自SortedMap,这个接口的有序性是指按照key的自然排序保证的有序性

  而key的自然排序又有两种实现方式一种是key实现Comparable接口,一种是构造方法传入Comparator比较器。

(2)TreeSet里面真的是使用TreeMap来存储元素的吗?

  通过源码分析我们知道TreeSet里面实际上是使用NavigableMap来存储元素,虽然大部分时候这个map确实是TreeMap,但不是所有时候都是TreeMap。

  因为有一个构造方法是TreeSet(NavigableMap<E,Object> m),而且这是一个非public方法,通过调用关系我们可以发现这个构造方法都是在自己类中使用的,比如下面这个:

    public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { return new TreeSet<>(m.tailMap(fromElement, inclusive)); }

  而这个m我们姑且认为它是TreeMap,也就是调用TreeMap的tailMap()方法:

    public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) { return new AscendingSubMap<>(this, false, fromKey, inclusive, true, null, true); }

可以看到,返回的是AscendingSubMap对象,这个类的继承链是怎么样的呢? 

      AscendingSubMap

  可以看到,这个类并没有继承TreeMap,不过通过源码分析也可以看出来这个类是组合了TreeMap,也算和TreeMap有点关系,只是不是继承关系。

  所以,TreeSet的底层不完全是使用TreeMap来实现的,更准确地说,应该是NavigableMap。


 

   对于HashSet是用Hash表来存储数据,而TreeSet是用二叉树存储数据

   在不需要排序的时候,还是建议优先使用HashSet,因为速度更快;二叉树需要排序就免不了跳转旋转,所以速度会很慢。

 

 

Guess you like

Origin www.cnblogs.com/FondWang/p/11938028.html