1.TreeSet介绍
TreeSet集合底层采用红黑树算法,会对存储的元素默认使用自然排序(从小到大).
注意: 必须保证TreeSet集合中的元素对象是相同的数据类型,否则报错.
2.TreeSet的排序规则
自然排序(从小到大):TreeSet调用集合元素的compareTo方法来比较元素的大小关系,然后将集合元素按照升序排列(从小到大).
注意:要求TreeSet集合中元素得实现java.util.Comparable接口.
各种数据类型自然排序规则
java.util.Comparable接口:可比较的.
覆盖 public int compareTo(Object o)方法,在该方法中编写比较规则.
在该方法中,比较当前对象(this)和参数对象o做比较(严格上说比较的是对象中的数据,比如按照对象的年龄排序).
this > o: 返回正整数. 1
this < o: 返回负整数. -1
this == o: 返回0. 此时认为两个对象为同一个对象.
--------------------------------------
在TreeSet的自然排序中,认为如果两个对象做比较的compareTo方法返回的是0,则认为是同一个对象.
从上图可知,基本上很多类都实现了这个接口,我们来看一下String类源码,可以看出String已经实现Comparable,并覆盖compareTo方法
举例:
import java.util.Set;
import java.util.TreeSet;
public class SetDemo4 {
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("a");
set.add("A");
set.add("abc");
set.add("B");
System.out.println(set);//打印结果,已经排好序了[A, B, a, abc],按照字符串的Unicode值排序
}
}
在这里我们如果要想自己定义的类在TreeSet中也能实现自然排序,那么就要根据上面的步骤来实现:
举个例子:首先定义一个Student类,这个类要实现Comparable接口,然后覆盖CompareTo方法,自定义自己需要排序的规则,比如我们这里按照学生的姓名的长度进行自然排序:
class Student implements Comparable<Student>{
private int id;
private String name;
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
/**
* 覆盖compareTo方法
* 根据学生的姓名长度排序
*/
public int compareTo(Student stu) {
if (this.getName().length()>stu.getName().length()) {
return 1;
}else if (this.getName().length()<stu.getName().length()) {
return -1;
}else {
return 0; //长度相同
}
}
}
测试:打印结果,姓名长度由短到长来排序的
import java.util.Set;
import java.util.TreeSet;
public class SetDemo4 {
public static void main(String[] args) {
Set<Student> set = new TreeSet<>();
set.add(new Student(1, "聂小倩"));
set.add(new Student(1, "西门吹雪"));
set.add(new Student(1, "哥"));
set.add(new Student(1, "孙斌"));
System.out.println(set);
//打印结果看下面,说明是按照名字长度从小到大的自然顺序来排序的
//[Student [id=1, name=哥], Student [id=1, name=孙斌], Student [id=1, name=聂小倩], Student [id=1, name=西门吹雪]]
}
}
定制排序(比如从大到小,按照名字的长短来排序):
在 TreeSet构造器中传递java.lang.Comparator对象.并 覆盖public int compare(Object o1, Object o2)再编写比较规则.
在TreeSet构造函数中,有一个构造函数可以传入一个比较器对象,他是一个接口,我们需要提供实现类,并覆盖compare方法再编写比较规则.
同样的,我们举个例子,也是按照学生姓名长度排序:
首先也是定义一个学生类:
class Student{
private int id;
private String name;
public Student(int id, String name) {
super();
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
}
然后定义比较器类:
import java.util.Comparator;
//比较器类
class NameLengthComparator implements Comparator<Student> {
/**
* 覆盖compare方法
* 比较规则:同样是根据学生的姓名长度排序
*/
public int compare(Student s1, Student s2) {
if (s1.getName().length() > s2.getName().length()) {
return 1;
} else if (s1.getName().length() < s2.getName().length()) {
return -1;
} else {
return 0;
}
}
}
测试:
import java.util.Set;
import java.util.TreeSet;
public class SetDemo5 {
public static void main(String[] args) {
//创建set对象的时候要传入比较器类对象
Set<Student> set = new TreeSet<>(new NameLengthComparator());
set.add(new Student(1, "聂小倩"));
set.add(new Student(1, "西门吹雪"));
set.add(new Student(1, "哥"));
set.add(new Student(1, "孙斌"));
System.out.println(set);
}
}
打印结果:
[Student2 [id=1, name=哥], Student2 [id=1, name=孙斌], Student2 [id=1, name=聂小倩], Student2 [id=1, name=西门吹雪]]
既然是定制排序,你可以修改排序规则,按照从长到短来排序,只需要修改比较器类的实现规则
import java.util.Comparator;
//比较器类
class NameLengthComparator implements Comparator<Student> {
/**
* 覆盖compare方法
* 比较规则:同样是根据学生的姓名长度排序
*/
public int compare(Student s1, Student s2) {
if (s1.getName().length() < s2.getName().length()) {
return 1;
} else if (s1.getName().length() > s2.getName().length()) {
return -1;
} else {
return 0;
}
}
}
将if中的>和<修改一下就行了
对于TreeSet集合来说,要么使用自然排序,要么使用定制排序.
判断两个对象是否相等的规则:
自然排序: compareTo方法返回0;
定制排序: compare方法返回0;