java集合-TreeSet

一:基本概念

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
", tSet.size());

        // 导航方法
        // floor(小于、等于)
        System.out.printf("floor bbb: %s
", tSet.floor("bbb"));
        // lower(小于)
        System.out.printf("lower bbb: %s
", tSet.lower("bbb"));
        // ceiling(大于、等于)
        System.out.printf("ceiling bbb: %s
", tSet.ceiling("bbb"));
        System.out.printf("ceiling eee: %s
", tSet.ceiling("eee"));
        // ceiling(大于)
        System.out.printf("higher bbb: %s
", tSet.higher("bbb"));
        // subSet()
        System.out.printf("subSet(aaa, true, ccc, true): %s
", tSet.subSet("aaa", true, "ccc", true));
        System.out.printf("subSet(aaa, true, ccc, false): %s
", tSet.subSet("aaa", true, "ccc", false));
        System.out.printf("subSet(aaa, false, ccc, true): %s
", tSet.subSet("aaa", false, "ccc", true));
        System.out.printf("subSet(aaa, false, ccc, false): %s
", tSet.subSet("aaa", false, "ccc", false));
        // headSet()
        System.out.printf("headSet(ccc, true): %s
", tSet.headSet("ccc", true));
        System.out.printf("headSet(ccc, false): %s
", tSet.headSet("ccc", false));
        // tailSet()
        System.out.printf("tailSet(ccc, true): %s
", tSet.tailSet("ccc", true));
        System.out.printf("tailSet(ccc, false): %s
", 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
", str);

        // 打印TreeSet
        System.out.printf("TreeSet:%s
", tSet);

        // 遍历TreeSet
        for(Iterator<String> iter = tSet.iterator(); iter.hasNext(); ) {
            System.out.printf("iter : %s
", iter.next());
        }

        // 删除并返回第一个元素
        val = (String)tSet.pollFirst();
        System.out.printf("pollFirst=%s, set=%s
", val, tSet);

        // 删除并返回最后一个元素
        val = (String)tSet.pollLast();
        System.out.printf("pollLast=%s, set=%s
", val, tSet);

        // 清空HashSet
        tSet.clear();

        // 输出HashSet是否为空
        System.out.printf("%s
", tSet.isEmpty()?"set is empty":"set is not empty");
    }

}

运行结果:

TreeSet:[aaa, bbb, ccc, ddd, eee]
size : 5
floor bbb: bbb
lower bbb: aaa
ceiling bbb: bbb
ceiling eee: eee
higher bbb: ccc
subSet(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 : aaa
for each : bbb
for each : ddd
for each : eee
TreeSet:[aaa, bbb, ddd, eee]
iter : aaa
iter : bbb
iter : ddd
iter : eee
pollFirst=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);
		}
	}
}

运行结果:

accd
acdc
adcc
cacd
cadc
ccad
ccda
cdac
cdca
dacc
dcac
dcca
原文地址:https://www.cnblogs.com/csuwater/p/5404491.html