java集合-TreeSet

来源:互联网 发布:yum下载 编辑:程序博客网 时间:2024/06/06 02:16

一:基本概念

TreeSet基于 TreeMap 的 NavigableSet 实现。

  • 使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。
  • 此实现为基本操作(add、remove 和 contains)提供受保证的 log(n) 时间开销。
  • 如果要正确实现 Set 接口,则 set 维护的顺序(无论是否提供了显式比较器)必须与 equals 一致。(关于与 equals 一致 的精确定义,请参阅 Comparable 或 Comparator。)这是因为 Set 接口是按照 equals 操作定义的,但 TreeSet 实例使用它的 compareTo(或 compare)方法对所有元素进行比较,因此从 set 的观点来看,此方法认为相等的两个元素就是相等的。即使 set 的顺序与 equals 不一致,其行为也是 定义良好的;它只是违背了 Set 接口的常规协定。
  • TreeSet不是同步的。如果多个线程同时访问一个 TreeSet,而其中至少一个线程修改了该 set,那么它必须 外部同步。这一般是通过对自然封装该 set 的对象执行同步操作来完成的。如果不存在这样的对象,则应该使用 Collections.synchronizedSortedSet 方法来“包装”该 set。此操作最好在创建时进行,以防止对 set 的意外非同步访问: SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...));
  • 此类的 iterator 方法返回的迭代器是快速失败 的:在创建迭代器之后,如果从结构上对 set 进行修改,除非通过迭代器自身的 remove 方法,否则在其他任何时间以任何方式进行修改都将导致迭代器抛出 ConcurrentModificationException。因此,对于并发的修改,迭代器很快就完全失败,而不会冒着在将来不确定的时间发生不确定行为的风险。
  • 注迭代器的快速失败行为无法得到保证,一般来说,存在不同步的并发修改时,不可能作出任何肯定的保证。快速失败迭代器尽最大努力抛出 ConcurrentModificationException。

实现结构图如下:(来源互联网)

public class TreeSet<E>extends AbstractSet<E>implements NavigableSet<E>, Cloneable, Serializable

这里写图片描述
API 简单测试:

package com.csu.collection;import java.util.Iterator;import java.util.TreeSet;public class TreeSetTest {    public static void main(String[] args) {        // TODO Auto-generated method stub        testTreeSetAPIs();    }    public static void testTreeSetAPIs() {        String val;        TreeSet<String> tSet = new TreeSet<>();        tSet.add("aaa");        // Set中不允许重复元素,所以只会保存一个“aaa”        tSet.add("aaa");        tSet.add("bbb");        tSet.add("eee");        tSet.add("ddd");        tSet.add("ccc");        System.out.println("TreeSet:"+tSet);        // 打印TreeSet的实际大小        System.out.printf("size : %d\n", tSet.size());        // 导航方法        // floor(小于、等于)        System.out.printf("floor bbb: %s\n", tSet.floor("bbb"));        // lower(小于)        System.out.printf("lower bbb: %s\n", tSet.lower("bbb"));        // ceiling(大于、等于)        System.out.printf("ceiling bbb: %s\n", tSet.ceiling("bbb"));        System.out.printf("ceiling eee: %s\n", tSet.ceiling("eee"));        // ceiling(大于)        System.out.printf("higher bbb: %s\n", tSet.higher("bbb"));        // subSet()        System.out.printf("subSet(aaa, true, ccc, true): %s\n", tSet.subSet("aaa", true, "ccc", true));        System.out.printf("subSet(aaa, true, ccc, false): %s\n", tSet.subSet("aaa", true, "ccc", false));        System.out.printf("subSet(aaa, false, ccc, true): %s\n", tSet.subSet("aaa", false, "ccc", true));        System.out.printf("subSet(aaa, false, ccc, false): %s\n", tSet.subSet("aaa", false, "ccc", false));        // headSet()        System.out.printf("headSet(ccc, true): %s\n", tSet.headSet("ccc", true));        System.out.printf("headSet(ccc, false): %s\n", tSet.headSet("ccc", false));        // tailSet()        System.out.printf("tailSet(ccc, true): %s\n", tSet.tailSet("ccc", true));        System.out.printf("tailSet(ccc, false): %s\n", tSet.tailSet("ccc", false));        // 删除“ccc”        tSet.remove("ccc");        // 将Set转换为数组        String[] arr = (String[])tSet.toArray(new String[0]);        for (String str:arr)            System.out.printf("for each : %s\n", str);        // 打印TreeSet        System.out.printf("TreeSet:%s\n", tSet);        // 遍历TreeSet        for(Iterator<String> iter = tSet.iterator(); iter.hasNext(); ) {            System.out.printf("iter : %s\n", iter.next());        }        // 删除并返回第一个元素        val = (String)tSet.pollFirst();        System.out.printf("pollFirst=%s, set=%s\n", val, tSet);        // 删除并返回最后一个元素        val = (String)tSet.pollLast();        System.out.printf("pollLast=%s, set=%s\n", val, tSet);        // 清空HashSet        tSet.clear();        // 输出HashSet是否为空        System.out.printf("%s\n", tSet.isEmpty()?"set is empty":"set is not empty");    }}

运行结果:

TreeSet:[aaa, bbb, ccc, ddd, eee]size : 5floor bbb: bbblower bbb: aaaceiling bbb: bbbceiling eee: eeehigher bbb: cccsubSet(aaa, true, ccc, true): [aaa, bbb, ccc]subSet(aaa, true, ccc, false): [aaa, bbb]subSet(aaa, false, ccc, true): [bbb, ccc]subSet(aaa, false, ccc, false): [bbb]headSet(ccc, true): [aaa, bbb, ccc]headSet(ccc, false): [aaa, bbb]tailSet(ccc, true): [ccc, ddd, eee]tailSet(ccc, false): [ddd, eee]for each : aaafor each : bbbfor each : dddfor each : eeeTreeSet:[aaa, bbb, ddd, eee]iter : aaaiter : bbbiter : ddditer : eeepollFirst=aaa, set=[bbb, ddd, eee]pollLast=eee, set=[bbb, ddd]set is empty

二:源码分析

1:变量定义:

NavigableMap对象,后边的集合操作就是基于它来操作的。

private transient NavigableMap<E,Object> m;

2:构造函数

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

创建一个空集,我们可以看出这个集合采用TreeMap来构造,以集合的值为Treemap的Key,因此集合不能存储重复的数据,这个构造函数使得集合排序按照TreeMap的自然顺序。

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

构造一个新的空 TreeSet,它根据指定比较器进行排序。也就是说,我们可以通过自己实现comparator接口来自定义排序。

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

构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序进行排序。我们可以看出通过调用addAll()方法将这个数据插入到集合中。

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

同样的道理,构造一个包含SortedSet的集合。
3:主要方法分析:
iterator():

public Iterator<E> iterator() {        return m.navigableKeySet().iterator();    }

我们可以看出TreeSet的迭代器是通过 NavigableMap对象的中KeySet方法获取的。
contains():

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

调用的事map的containsKey()方法;
add();

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

也是直接调用map的方法。
addAll():

public  boolean addAll(Collection<? extends E> c) {        // Use linear-time version if applicable        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))) {                           //还是通过调用TreeMap的方法添加元素                map.addAllForTreeSet(set, PRESENT);                return true;            }        }        return super.addAll(c);    }

将指定 collection 中的所有元素添加到此 set 中。

应用实例

通TreeSet实现全排列
测试端:

mport java.util.Iterator;import java.util.Set;import java.util.TreeSet;public class TreeSetTest1 {    public static void main(String[] args) {        // TODO Auto-generated method stub      Set<String> set=new TreeSet<>();      char []arr={'a','c','c','d'};      permutations(set, arr, 0, arr.length);      Iterator<String> iterator=set.iterator();      while(iterator.hasNext())      {          System.out.println(iterator.next());      }    }    public static void swap(char[] arr,int x,int y)    {        char temp=arr[x];        arr[x]=arr[y];        arr[y]=temp;    }    public static void permutations(Set<String> set,char[] arr,int start,int end)    {        if(start==end-1)        {            set.add(new String(arr));        }        for(int i=start;i<end;i++)        {            swap(arr, start, i);            permutations(set, arr, start+1, end);            swap(arr, start, i);        }    }}

运行结果:

accdacdcadcccacdcadcccadccdacdaccdcadaccdcacdcca
0 0
原创粉丝点击