Java集合容器系列09 - TreeSet

本文介绍了TreeSet,它基于TreeMap实现,用自然顺序或比较器排序,add等操作时间复杂度为log(n),非线程同步。还说明了其数据结构,继承AbstractSet、实现多个接口。最后对其构造函数和成员方法进行源码分析,指出操作依赖底层TreeMap。

一、TreeSet介绍

    TreeMap是底层基于TreeMap的NavigableSet实现,容器的元素存储在TreeMap键值对映射的key中,它使用元素的自然顺序或者传入的比较器Comparator对元素进行排序。它为基本操作例如add、remove、contain提供了log(n)的时间复杂度保证。注意TreeSet不是线程同步的容器,如果有多个线程同时访问它,且至少有一个线程修改了容器的结构,那么他必须在外部进行同步处理。一般都是通过对自然封装该Set实例的对象进行同步操作来完成,如果没有这样的对象,那么可以使用Collections.synChronizedSortedSet包装TreeSet为一个线程安全的容器。

    该TreeSet容器返回的迭代器是快速失败的(fail-fast),即在生成迭代器之后,如果该容器发生了结构部性修改除了通过迭代iterator.remove方法删除元素之外,迭代器将会抛出ConcurrentModificationException异常,该异常并不能绝对保证,应该只用于检测异常。

 

二、TreeSet数据结构

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable
{
    /** 内部TreeMap实例 **/
    private transient NavigableMap<E,Object> m;

    //静态对象充当TreeMap实例中的键值对中的value,所有key的value都是该对象
    private static final Object PRESENT = new Object();

}

    TreeSet继承自AbstractSet,AbstractSet提供了Set的一些基本方法实现,大大减少实现TreeSet的工作量,此外它实现了NavigableSet接口,扩展了倒序、获取给定目标最接近匹配等功能,实现了Clonable支持克隆、java.io.Serializable支持序列化

三、TreeSet的源码分析

1 - 构造函数
    /**
     * 构造方法,指定NavigableMap实例
     */
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }

    /**
     * 无参构造方法,默认创建一个TreeMap实例
     */
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }

    /**
     * 构造方法,创建一个空的TreeMap实例并按照方法指定的比较器对元素进行排序
     */
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }

    /**
     * 构造方法,创建一个空的TreeSet实例,并将方法指定集合c的所有元素填充到TreeSet实例中
     */
    public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
    }

    /**
     * 构造方法,创建一个空的TreeSet实例,比较器取方法参数SortedSet对象的s的内部比较器,
     * 将容器s中的所有元素填充到内部TreeMap实例
     */
    public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
    }

    通过对TreeSet构造函数的分析,我们可以了解到TreeSet的底层与HashSet类似,只不过它的底层存储结构是一个NavagableMap实例,一般是TreeMap对象,所有TreeSet的操作最终都是反映到底层对TreeMap的操作。

2 - 其他成员方法
    /**
     * 返回一个遍历当前容器元素的迭代器
     */
    public Iterator<E> iterator() {
        return m.navigableKeySet().iterator();
    }

    /**
     * 判断当前容器是否为空
     */
    public boolean isEmpty() {
        return m.isEmpty();
    }

    /**
     * 返回当前容器是否包含指定元素
     */
    public boolean contains(Object o) {
        return m.containsKey(o);
    }

    /**
     * 添加元素
     */
    public boolean add(E e) {
        return m.put(e, PRESENT)==null;
    }

    /**
     * 删除元素
     */
    public boolean remove(Object o) {
        return m.remove(o)==PRESENT;
    }

    /**
     * 获取容器第一个元素
     */
    public E first() {
        return m.firstKey();
    }

    /**
     * 获取容器最后一个元素
     */
    public E last() {
        return m.lastKey();
    }

    通过对TreeSet成员方法的分析,我们可以发现它们的实现完全依赖于底层的NavigableMap实例(一般情况下可以简单视为TreeMap实例),容器元素对应的是TreeMap实例键值对的Key,若想研读底层实现可以直接去研读TreeMap响应方法的源码。

转载于:https://my.oschina.net/zhangyq1991/blog/1935346

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值