特点
- TreeSet 底层是采用 TreeMap 实现的一种 Set 集合;
typescript
//和HashSet一样,PRESENT的目的是为了占位
private static final Object PRESENT = new Object();
public boolean add(E e) {
return this.m.put(e, PRESENT) == null;
}
- 单线程安全,多线程不安全;
- 使用无参构造器创建TreeSet时,是无序的(存入取出顺序不一致);
csharp
public TreeSet() {
this((NavigableMap)(new TreeMap()));
}
- 如果需要排序,需要指定排序规则
java
/**
* 有参构造函数
* 使用带 comparator 的 TreeMap 初始化
* @param comparator 比较器
*/
public TreeSet(Comparator<? super E> comparator) {
this((NavigableMap)(new TreeMap(comparator)));
}
TreeSet 在存对象的时候,如果不指定自定义的比较器,那么存储的对象必须实现 Comparable 接口,以Integer类为例:
java
public final class Integer extends Number implements Comparable<Integer> {
//省略其他代码
//......
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
}
TreeSet 底层插入元素的过程简述
TreeSet(TreeMap)底层是二叉树实现的,当存储元素的时候,会调用比较规则方法,将新元素和二叉树上已有的元素进行一一比较。
- 如果要插入的元素比当前元素小、就到左子树去比较;
- 如果比当前元素大,就到右子树去比较,直到当前元素的左或者右子树为空,就插入此元素;
- 如果在比较过程中,出现当前元素等于要插入的元素,那么此元素不插入;
注意:基本数据类型,不需要定义比较器,只有当以树作为存储结构时,而且添加的是引用对象时,才需要定义比较器;
定义比较器的方式有两种:
实现 内部比较器Comparable 接口
typescript
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
//按照学生年龄排序
@Override
public int compareTo(Student o) {
return this.age - o.age;
}
}
实现 Comparable 接口的类必须实现 compareTo(Object obj) 方法,两个对象通过 compareTo 方法的返回值来比较大小 :
- 如果当前对象 this 大于形参对象 obj 则返回正整数;
- 如果当前对象 this 小于 形参对象 obj则返回 负整数;
- 如果当前对象 this 等于 形参对象 obj 则返回零;
自定义外部比较器Comparator接口
csharp
public class DemoTreeSet {
public static void main(String[] args) {
//匿名内部类实现比较器:首先按照年龄进行排序,如果年龄相同,我们再按照名字的长度进行排序(升序)
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int num = o1.getAge() - o2.getAge();
return num == 0 ? o1.getName().length() - o2.getName().length() : num;
}
});
ts.add(new Student("张廷玉",43));
ts.add(new Student("纳兰明珠",80));
ts.add(new Student("索额图",79));
ts.add(new Student("苏麻喇姑",79));
for (Student student : ts) {
System.out.println(student);
}
}
}
通过new一个匿名内部类的方式,定义一个外部比较器Comparator接口对象,重写 compare(Object o1,Object o2) 方法,比较 o1 和 o2 的大小:
- 如果方法返回正整数,则表示 o1 大于 o2 ;
- 如果方法返回 0 ,表示相等;
- 如果方法返回负整数,表示o1 小于 o2 。