自然排序与比较器排序
自然排序(Comparable)
java.lang.Comparable;
Comparable是一个抽象类,需要类实现它,才可以使用自然排序。 Comparable 同时是泛型,需要实现它的public int compareTo()方法.
以TreeSet举例,TreeSet有两种使用排序的方法,一种是类型自带自然排序接口Comparable,如:Integer,String等,都是实现了Comparable接口,所以可以直接添加对象进TreeSet中,TreeSet通过他们本身自带的compareTo()接口实现Set的有序排序;
//TreeSet的无参构造方法,使用了其包含的类中的Comparable接口实现排序
TreeSet<Student> ts = new TreeSet<Student>();
/**
* class Student implements Comparable<Student>{
* private int age;
*
* @Override
* public int compareTo(Student s) {
* return 0;
* }
* }
* */
//Student类中本身没有实现Comparable接口,我们可以自定义Comparable接口,实现我们想要的排序规则。
TreeSet中使用自然排序,会将当前对象和上一个对象进行比较。
@Override
public int compareTo(Student s) {
//当前对象和上一个对象
//当前对象的年龄减去上一个对象的年龄
int num = this.age - s.age;
//如果结果是一个整数,那么代表当前年龄大于上一个年龄,返回正数,这时候就会将当前对象添加到TreeSet中
//因为是整数,TreeSet就默认添加到上一个元素的后面,也就是直接插入
//这样判断就构成了升序的排序
//如果返回的是一个负数,那么代表当前对象小于上一个对象,就会将当前对象插入到上一个对象之前,以此来保证升序
return num;
}
如果要使TreeSet完成降序的操作(从高到底):
@Override
public int compareTo(Student s) {
//当前对象和上一个对象
//上一个对象减去当前对象,如果是整数,那么代表上一个对象大于当前对象
int num = s.age - this.age;
//这时候是整数,那么就会将当前的元素添加到上一个元素之后,就完成了降序的排序(从高到低)
//如果得到的是一个负数,那么就代表上一个元素小于当前元素,所以就会将当前元素添加到上一个元素之前,以此来保证有序
return num;
}
如果得到的结果是0呢?那么TreeSet就认为比较的两个是相同的对象,就不会进行添加操作。
总结:自然排序接口就是通过类来实现排序接口,使得类在需要排序的地方可以直接使用类的排序方法进行排序,但这种排序方式是固定的,也就是这个类只能使用该排序方法进行排序,如果想要不同方法来对这个类进行排序就无法实现。
比较器排序(Compareator)
java.util.Comparator
Comparator比较器排序,它的好处就是将类和自然排序进行了分离,在要使用到排序的时候,在创建对象的时候给它提供一个比较器即可。
以TreeSet举例,通过匿名内部类的方法创建比较器:
//TreeSet的有参构造方法,通过提供比较器排序来实现TreeSet的排序,这样TreeSet的实现类就无需实现自然排序接口
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
//以匿名内部类方式在创建TreeSet对象的时候提供比较器
@Override
public int compare(Student s1, Student s2) {
//s1就是当前的对象,s2就是TreeSet中的上一个对象
//还是拿当前对象和上一个对象进行比较
int num = s1.getAge() - s2.getAge();
//当前对象的年龄减去上一个对象的年龄
//如果是正数,那么代表当前对象大于上一个对象,
//就会将当前对象添加到上一个对象之后,也就是直接插入到TreeSet的末尾
return num;
}
});
比较器使用的升序排序(从低到高),如果想要使用降序,那么上一个对象的具体值减去当前对象的具体值即可完成降序排序,如:
//TreeSet的有参构造方法,通过提供比较器排序来实现TreeSet的排序,这样TreeSet的实现类就无需实现自然排序接口
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
//以匿名内部类方式在创建TreeSet对象的时候提供比较器
@Override
public int compare(Student s1, Student s2) {
//s1就是当前的对象,s2就是TreeSet中的上一个对象
//还是上一个对象和当前对象进行比较
int num = s2.getAge() - s1.getAge();
//当前上一个对象的年龄减去当前对象的年龄
//如果是正数,那么代表上一个对象大于当前对象
//就会将当前对象添加到上一个对象之后,也就是直接插入到TreeSet的末尾
//这样就实现了降序的排序
return num;
}
});
同自然排序一样,如果返回的是0,那么TreeSet就认为是相同元素,就不进行添加,这就是TreeSet能实现排序和去重的要点。
Java 8 的Lambda语法,简化操作:
假设我们有一个List,需要实现将其中的元素进行降序排序,我们可用通过Collections.sort方法来排序List,同时提供一个比较器进行升序的排序,下面贴上代码:
正常new一个比较器:
import java.util.*;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for(int i = 1;i<20;i++) {
list.add(i);
}
//使用Collections工具类进行排序
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
//打印查看list中的元素排序方式
System.out.println(list);
}
}
结果:
实现了升序排序。
接下来我们使用Lambda语法:
import java.util.*;
public class Main {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
for(int i = 1;i<20;i++) {
list.add(i);
}
//使用Collections工具类进行排序
Collections.sort(list,(o1,o2)->o2-o1);
//打印查看list中的元素排序方式
System.out.println(list);
}
}
结果:
同样实现了升序排序。
我们发现,可用使用Java 8提供的Lambda语法,简化我们new比较器的操作,其中第一个括号里面放的就是我们重写compare方法的两个参数,第二个括号就是我们compare方法中的返回值即可。
总结
比较器排序不需要类实现自然排序接口,可以通过提供比较器的方法提供比较规则,无需该类实现自然排序接口。
也就是该类可以使用比较器来实现多种比较排序,可以使用多种排序规则进行该类的排序。也就是将比较排序算法与具体的类分离开了,这样避免了一个类只能使用一种比较排序的算法。
使得我们可以根据使用情况选择比较规则。
参考资料:
(6条消息) Java中的排序比较方式:自然排序和比较器排序_littledownload的博客-CSDN博客)