TreeSet集合的自然排序与比较器排序、Comparable接口的compareTo()方法

时间:2022-09-24 07:58:08

【自然排序】

 package com.hxl;

 public class Student implements Comparable<Student> {

     private String name;
private int age; public Student() {
super();
} public Student(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public int compareTo(Student s) {
// 先让两个对象的age属性做差比较,这个是主要排序条件
int num = this.age - s.age;
// 若age属性相同,再比较name属性(String类本身实现了Comparable接口)
// 即在主要排序条件相同的情况下,次要排序条件起作用
int flag = num == 0 ? this.name.compareTo(s.name) : num;
// 返回比较结果
return flag;
}
}
 package com.hxl;

 import java.util.TreeSet;

 public class Test {
public static void main(String[] args) {
//这里使用的无参构造实例化TreeSet集合,则默认启用的是自然排序
TreeSet<Student> ts = new TreeSet<Student>();
ts.add(new Student("cc", 11));
ts.add(new Student("ee", 11));
ts.add(new Student("cc", 22));
ts.add(new Student("aa", 22));
ts.add(new Student("bb", 11)); for (Student s : ts) {
System.out.println(s.getName()+"_"+s.getAge());
} /*
为什么TreeSet集合中的元素既唯一又有序呢?
原因是它在存储元素的时候就是有序存储的(红黑树结构存储)
TreeSet的add()方法底层依赖的是Comparable的compareTo方法
这里就是说元素类本身要有自己的compareTo方法
所以元素类本身必须实现Comparable接口,重写compareTo方法
compareTo方法有个特点:它返回的是int型数据,结果有三类负数、0、正数
例如:(Java中一些常见的有比较意义的一些类都实现了Comparable接口,如Integer类)
Integer a = new Integer(10);
Integer b = new Integer(20);
int num = a.compareTo(b); //因为a小于b,所以num返回的是负数
而TreeSet的add()方法这样理解此返回值:
即返回负数则比根节点小,元素在此集合中唯一,元素存放根的左孩子
返回正数则比根节点大,元素在此集合中唯一,元素存放根的右孩子
返回0则表示,元素相同,在此集合中不唯一,故而丢掉不存放
由此可见,我们的重写的compareTo()方法决定了TreeSet集合中元素的去留和顺序!
*/
}
}

【比较器排序(外部类实现)】

 package com.hxl;

 public class Student{

     private String name;
private int age; public Student() {
super();
} public Student(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
}
 package com.hxl;

 import java.util.Comparator;

 public class MyComparator implements Comparator<Student> {

     @Override
public int compare(Student s1, Student s2) {
// 先让两个对象的age属性做差比较,这个是主要排序条件
int num = s1.getAge() - s2.getAge();
// 若age属性相同,再比较name属性(String类本身实现了Comparable接口)
// 即在主要排序条件相同的情况下,次要排序条件起作用
int flag = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
// 返回比较结果
return flag;
}
}
 package com.hxl;

 import java.util.TreeSet;

 public class Test {
public static void main(String[] args) {
//这里使用TreeSet(Comparator comparator)构造实例化TreeSet集合,则启用的是指定比较器排序
TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
ts.add(new Student("cc", 11));
ts.add(new Student("ee", 11));
ts.add(new Student("cc", 22));
ts.add(new Student("aa", 22));
ts.add(new Student("bb", 11)); for (Student s : ts) {
System.out.println(s.getName()+"_"+s.getAge());
}
}
}

【比较器排序(内部类实现,如果只使用一次的话)】

 package com.hxl;

 public class Student{

     private String name;
private int age; public Student() {
super();
} public Student(String name, int age) {
super();
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
}
 package com.hxl;

 import java.util.Comparator;
import java.util.TreeSet; public class Test {
public static void main(String[] args) {
//如果一个方法的参数是接口,那么真实想要的是其实是接口实现类的对象
//这里的对象只用一次,专门定义一个外部类显得麻烦
//匿名内部类可以实现这个需求
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>(){
public int compare(Student s1, Student s2) {
// 先让两个对象的age属性做差比较,这个是主要排序条件
int num = s1.getAge() - s2.getAge();
// 若age属性相同,再比较name属性(String类本身实现了Comparable接口)
// 即在主要排序条件相同的情况下,次要排序条件起作用
int flag = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
// 返回比较结果
return flag;
}
});
ts.add(new Student("cc", 11));
ts.add(new Student("ee", 11));
ts.add(new Student("cc", 22));
ts.add(new Student("aa", 22));
ts.add(new Student("bb", 11)); for (Student s : ts) {
System.out.println(s.getName()+"_"+s.getAge());
}
}
}

【注】开发中会用最后一种,因为第一种只有固定的排序方式,第二种每次都要定义外面类显得麻烦。