Java编程拾遗『TreeSet』

上篇文章我们讲了TreeMap的实现,熟悉了TreeMap的一大重要特征——保证键值对之间根据键的有序性。之前在讲HashSet时,我们知道HashSet是通过HashMap实现的。同样的道理,TreeSet其实也是基于TreeMap实现的。TreeSet相比于HashSet,一个突出的特点就是,可以保证元素之间的顺序。TreeSet类继承关系如下:

TreeSet继承了AbstractSet抽象类,可以方便地实现Set接口的基本方法。另外TreeSet实现了NavigableSet接口,NavigableSet接口又继承了SortedSet接口,所以TreeSet可以很方便的获取第一个、最后一个或者某个区间的元素。

1. 使用规则

1.1 TreeSet基本定义

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{

    private transient NavigableMap<E,Object> m;

    private static final Object PRESENT = new Object();

    //methods
}
  • m:用于实现TreeSet的NavigableMap对象,TreeSet可以看做是所有Value都为默认值的一个NavigableMap的key组成的Set
  • PRESENT:TreeSet内部NavigableMap的value默认值

1.2 构造函数

S.N.方法说明
1public TreeSet()默认构造函数,调用TreeMap的默认构造函数,实例化TreeMap对象赋值给m
2public TreeSet(Collection<? extends E> c)通过Collection对象实例化TreeSet,m也是通过TreeMap的默认构造函数构造出来的
3public TreeSet(Comparator<? super E> comparator)通过TreeMap(Comparator<? super K> comparator)构造函数构造TreeMap对象赋值给m
4public TreeSet(SortedSet<E> s)通过SortedMap对象构造TreeSet

1.3 SortedSet

S.N.方法说明
1Comparator<? super E> comparator()返回SortedSet集合中元素之间用于比较的Comparator,如果SortedMap内部comparator为null(使用自然排序),返回null
2E first()返回SortedSet集合中第一个元素,如果集合为空,抛NoSuchElementException异常
3E last()返回SortedSet集合中最后一个元素,如果集合为空,抛NoSuchElementException异常
4SortedSet<E> headSet(E toElement)返回SortedSet中小于toElement的所有元素组成的子SortedSet视图,对视图的改变会影响SortedSet的内容
5SortedSet<E> tailSet(E fromElement)返回SortedSet大于等于fromElement的所有元素组成的子SortedSet视图,对视图的改变会影响SortedSet的内容
6SortedSet<E> subSet(E fromElement, E toElement)返回SortedSet中大于等于fromElement小于toElement的所有元素组成的子SortedSet视图,对视图的改变会影响SortedSet的内容
7default Spliterator<E> spliterator()Java8新方法,返回SortedSet的Spliterator迭代器

1.4 NavigableSet

S.N.方法说明
1E lower(E e)返回NavigableSet中严格小于e的最大元素
2E higher(E e)返回NavigableSet中严格大于e的最小元素
3E floor(E e)返回NavigableSet中小于等于e的最大元素
4E ceiling(E e)返回NavigableSet中大于等于e的最小元素
5NavigableSet<E> descendingSet()返回NavigableSet所有元素逆序的NavigableSet视图,对视图的改变会影响NavigableSet的内容
6Iterator<E> descendingIterator()返回NavigableSet的逆序Iterator迭代器,等效于descendingSet().iterator()
7Iterator<E> iterator()返回NavigableSet的正向迭代器
8E pollFirst()删除并返回NavigableSet中第一个元素,如果NavigableSet为空,返回null
9E pollLast()删除并返回NavigableSet中最后一个元素,如果NavigableSet为空,返回null
10NavigableSet<E> headSet(E toElement, boolean inclusive)返回NavigableSet中小于toElement的所有元素组成的子NavigableSet视图,inclusive表示是否包含边界,
对视图的改变会影响SortedMap的内容
10NavigableSet<E> tailSet(E fromElement, boolean inclusive)返回NavigableSet中大于fromElement的所有元素组成的子NavigableSet视图,inclusive表示是否包含边界,
对视图的改变会影响SortedMap的内容
11NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
E toElement, boolean toInclusive)
返回NavigableSet中大于fromElement小于toElement的所有元素组成的子NavigableSet视图,
fromInclusive、toInclusive表示是否包含边界,对视图的改变会影响SortedMap的内容

1.5 Set

S.N.方法说明
1boolean add(E e)向Set中添加一个元素
2boolean addAll(Collection<? extends E> c)将Collection中的元素添加到Set中
3boolean contains(Object o)判断Set中是否包含o元素
4boolean containsAll(Collection<?> c)判断Collection中的元素是否全部存在于Set中
5boolean equals(Object o)equals方法
6int hashCode()hashCode方法
7boolean isEmpty()判断Set是否为空
8Iterator<E> iterator()返回Set的单向Iterator迭代器
9boolean remove(Object o)删除Set中的元素o
10boolean removeAll(Collection<?> c)删除Set中包含的Collection的所有元素,如果c也为Set,表示求差集
11boolean retainAll(Collection<?> c)保留Set中包含的Collection的所有元素,如果c也为Set,表示求交集
12int size()返回Set元素个数
13default Spliterator<E> spliterator()返回Set的并行流Spliterator迭代器
14Object[] toArray()Set转Object[]数组
15<T> T[] toArray(T[] a)Set转特定类型数组

2. 实现源码分析

2.1 构造函数

public TreeSet() {
    this(new TreeMap<E,Object>());
}

默认构造函数调用了另一个构造函数,传入的参数为调用TreeMap的默认构造函数创建的一个TreeMap对象(实例化得到的TreeMap comparator为null),该情形下要求TreeSet中的元素实现了Comparable接口。

TreeSet(NavigableMap<E,Object> m) {
    this.m = m;
}

该构造函数的访问权限为包访问权限,将上述TreeMap赋值给TreeSet内部的成员变量m。

public TreeSet(Collection<? extends E> c) {
    this();
    addAll(c);
}

该构造函数通过Collection对象实例化TreeSet,实现也比较简单,就是调用上述无参构造函数,对成员变量m赋值为一个空的TreeMap,然后调用addAll方法,将Collection中所有的元素添加到m中,从而达到实例化TreeSet的效果,该情形下也要求Collection中的元素实现了Comparable接口。

public TreeSet(Comparator<? super E> comparator) {
    this(new TreeMap<>(comparator));
}

这种形式的构造函数,通过Comparator对象初始化TreeSet,其实就是调用TreeMap的TreeMap(Comparator<? super K> comparator)构造函数得到一个TreeMap对象,并将该对象赋值给TreeSet内部成员变量m。

public TreeSet(SortedSet<E> s) {
    this(s.comparator());
    addAll(s);
}

这种形式的构造函数,通过SortedSet对象初始化TreeSet,就是调用上述TreeSet(Comparator<? super E> comparator)构造函数,对内部成员变量m赋值后,调用addAll方法,将SortedSet中所有的元素通过调用addAll方法添加到m中。

2.2 boolean add(E e)

public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

就是调用TreeMap的put方法,e为TreeMap键值对的key,键值对值为静态Object常量PRESENT,put返回null表示原来没有对应的键,添加成功了。

2.3 boolean remove(Object o)

public boolean remove(Object o) {
    return m.remove(o)==PRESENT;
}

就是调用TreeMap的remove方法,返回值为PRESENT表示原来有对应的键且删除成功了。

2.4 boolean contains(Object o)

public boolean contains(Object o) {
    return m.containsKey(o);
}

就是调用TreeMap的containsKey方法,判断TreeMap中是否包含对应的键。

2.5 NavigableSet<E> subSet

public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,
                              E toElement,   boolean toInclusive) {
    return new TreeSet<>(m.subMap(fromElement, fromInclusive,
                                   toElement,   toInclusive));
}

调用TreeMap的subMap方法获取TreeMap的子视图,然后调用TreeSet的构造函数初始化TreeSet。TreeMap的subMap方法的返回值是一个NavigableMap对象,该对象内部的红黑树其实跟原TreeMap内部的红黑树共享同一片内存空间,所以subMap方法返回的是原TreeMap的一个子视图,对视图的修改会同步影响到原TreeMap。调用TreeSet的构造函数,将subMap方法返回的NavigableMap对象作为参数传入,所以subSet是整个TreeSet的子视图。

通过以上方法可以发现,其实TreeSet跟HashSet一样,实现都比较简单。HashSet主要通过调用HashMap的方法来实现,TreeSet主要是通过调用NavigableMap的方法来实现。

 3. TreeSet特点

TreeSet内部是通过TreeMap实现的,所以也可以讲TreeSet底层是通过红黑树实现的。TreeSet有以下特点:

  • TreeSet实现了Set接口,具有Set的一切特性,比如不存在重复元素
  • TreeSet相比于HashSet,元素之间是有序的,由于TreeSet实现了NavigableSet接口,所以可以很方便的操作第一个、最后一个或一定范围内的元素
  • TreeSet是基于TreeMap实现的,所以添加、删除、判断元素是否存在,效率比较高,时间复杂度为为O(logN)

参考链接:

  1. Java API源码
  2. 《Java编程的逻辑》
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值