文章目录
Java的JDK中提供了强大的接口,其中关于自定义排序的方法主要有如下几类:
Arrays中sort方法
sort方法有很多的重载,实现了不同数据类型的排序和自定义排序;
基本数据类型的排序
基本数据类型的排序直接使用相应的方法sort(int[] a),支持的数据类型数组包括:
- char[] a;
- byte[] a;
- short[] a;
- int[] a;
- long[] a;
- float[] a;
- double[] a;
默认为升序排序,自定义排序方式下面另说;
排序方式使用的都是快速排序的一个改动版:Dual-Pivot Quicksort,时间复杂度O(nlog(n));
以上方法都有一个相应的孪生兄弟,如上述方法sort(int[] a)的重载方法就是sort(int[] a, int fromIndex, int toIndex),它的作用是指定需要排序的区间,区间为左闭右开:
public class BasicSort {
public static void main(String[] args){
int[] a = new int[]{5,4,6,3,7,2,8,1,9,0};
System.out.println("排序前:" + Arrays.toString(a));
Arrays.sort(a);
System.out.println("排序后:" + Arrays.toString(a));
a = new int[]{5,4,6,3,7,2,8,1,9,0};
System.out.println("自定义区间排序前:" + Arrays.toString(a));
Arrays.sort(a, 0, 5);
System.out.println("自定义区间排序后:" + Arrays.toString(a));
}
}
排序前:[5, 4, 6, 3, 7, 2, 8, 1, 9, 0]
排序后:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
自定义区间排序前:[5, 4, 6, 3, 7, 2, 8, 1, 9, 0]
自定义区间排序后:[3, 4, 5, 6, 7, 2, 8, 1, 9, 0]
其中需要注意的是Float、Double类型各自使用了其类中内置定义的比较函数,如Float中规则为 -0.0f < 0.0f,Float.NaN == Float.NaN;
float[] b = new float[]{1.1f, 2.2f, 0.0f, -0.0f, Float.NaN, 1000f, Float.NEGATIVE_INFINITY, Float.NaN};
System.out.println("自定义区间排序前:" + Arrays.toString(b));
Arrays.sort(b);
System.out.println("自定义区间排序后:" + Arrays.toString(b));
自定义区间排序前:[1.1, 2.2, 0.0, -0.0, NaN, 1000.0, -Infinity, NaN]
自定义区间排序后:[-Infinity, -0.0, 0.0, 1.1, 2.2, 1000.0, NaN, NaN]
Object类型的排序
Object类型数据的排序需要实现Comparable接口并实现其中的compareTo方法;
主要是以下几种:
- 基本类型的包装类,其已经实现了Comparable接口;
- JDK中实现了Comparable接口的类,如String;
- 自定义类并实现接口Comparable;
下面代码中需要用到的学生类:
public class Student implements Comparable<Student>{
public int id; // 学号,为了获取方便直接定义为public
public int grade; // 分数
public Student(int id, int grade) {
this.id = id;
this.grade = grade;
}
/**
* 排序规则:
* 分数高的排前面,分数相同的学号小的排前面
* @param o
* @return
*/
@Override
public int compareTo(Student o) {
if(this.grade != o.grade){
return o.grade - this.grade;
}else{
return this.id - o.id;
}
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", grade=" + grade +
'}';
}
}
对对象列表排序:
public class CpmparableSort {
public static void main(String[] args) {
Student[] a = new Student[]{
new Student(1001, 60),
new Student(1002, 100),
new Student(1000, 60)
};
System.out.println("排序前:" + Arrays.toString(a));
Arrays.sort(a); // 使用实现Comparable接口定义的比较规则
System.out.println("排序后:" + Arrays.toString(a));
}
}
排序前:[Student{id=1001, grade=60}, Student{id=1002, grade=100}, Student{id=1000, grade=60}]
排序后:[Student{id=1000, grade=60}, Student{id=1001, grade=60}, Student{id=1002, grade=100}]
该排序是一个稳定的,自适应的,迭代归并的排序方式,实现基于TimSort,是一个基于插入排序和归并排序的自适应排序方式;
当然,它同样也有一个孪生的方法sort(Object[] a, int fromIndex, int toIndex),对左闭右开区间的元素进行排序;
根据指定比较器对对象进行排序
public static void sort(T[] a, Comparator<? super T> c),需要指定一个比较器Comparator,也就是对需要排序的元素指定排序规则;
如对二维数组排序,其中第二维只有两个元素,先按照第一个元素升序排序,第一个元素相等,按照第二个元素升序排序,也就是实现了多级排序;
public class ComparatorSort {
public static void main(String[] args) {
int[][] a = new int[][]{
{0, 3}, {1, 5}, {7, 5},
{1, 3}, {5, 6}, {9, 5}
};
System.out.println("排序前:");
for(int i=0; i<a.length; ++i){
System.out.println(Arrays.toString(a[i]));
}
/**
* 自定义比较器
* 二维数组,其中第二维只有两个元素,按前一个元素升序排序,前一个元素相同,则按后一个元素升序
*/
Arrays.sort(a, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if(o1[0] != o2[0]){
return o1[0] - o2[0];
}else{
return o1[1] - o2[1];
}
}
});
System.out.println("排序后:");
for(int i=0; i<a.length; ++i){
System.out.println(Arrays.toString(a[i]));
}
}
}
排序前:
[0, 3]
[1, 5]
[7, 5]
[1, 3]
[5, 6]
[9, 5]
排序后:
[0, 3]
[1, 3]
[1, 5]
[5, 6]
[7, 5]
[9, 5]
前面提到的基本类型,对元素的排序方式默认为升序,如果想要降序,则可以通过自定义排序器指定排序规则;
Object类型,若是没有实现Comparable接口或已经实现了Comparable接口但想要一种新的排序方式,就可以自定义比较器Comparator,实现自定义的排序;
public class ComparatorSort1 {
public static void main(String[] args) {
Student[] a = new Student[]{
new Student(1001, 60),
new Student(1002, 100),
new Student(1000, 60)
};
System.out.println("排序前:" + Arrays.toString(a));
/**
* 自定义比较器Comparator
* 按照学号升序,学号相同,按成绩升序
*/
Arrays.sort(a, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if(o1.id != o2.id){
return o1.id - o2.id;
}else{
return o1.grade - o2.grade;
}
}
});
System.out.println("排序后:" + Arrays.toString(a));
}
}
排序前:[Student{id=1001, grade=60}, Student{id=1002, grade=100}, Student{id=1000, grade=60}]
排序后:[Student{id=1000, grade=60}, Student{id=1001, grade=60}, Student{id=1002, grade=100}]
当然,这个方法也有一个孪生兄弟,也就是可以指定排序区间,同上。
Collections中sort方法
Collections中提供的方法,包括sort方法,都是为了给Collection接口下的各类使用的;包括两种:
- 类已经实现了Comparable接口:public static <T extends Comparable<? super T>> void sort(List list)
- 自定义比较器Comparator:public static void sort(List list, Comparator<? super T> c)
两者的用法和上述的基本相同,只不过对象用于集合;这两种方式都是基于List接口中方法default void sort(Comparator<? super E> c),其基于TimSort排序;
void sort(List list)
public static <T extends Comparable<? super T>> void sort(List list)
这种方式一定需要List中元素已经实现了Comparable接口,如基本数据类型的包装类,String等类,若是自定义类,则需要实现Comparable接口自定义排序方法;
void sort(List list, Comparator<? super T> c)
public static void sort(List list, Comparator<? super T> c)
这种方法使用时需要自定义比较器Comparator;
例:
public class CustomSort {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(5,4,6,3,7,2,8,1,9,0);
System.out.println("排序前:" + list);
Collections.sort(list);
System.out.println("排序后:" + list);
List<Student> stuList = Arrays.asList(
new Student(1001, 60),
new Student(1002, 100),
new Student(1000, 60)
);
System.out.println("排序前:" + stuList);
Collections.sort(stuList);
System.out.println("排序后:" + stuList);
System.out.println("排序前:" + stuList);
Collections.sort(stuList, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if(o1.id != o2.id){
return o1.id - o2.id;
}else{
return o1.grade - o2.grade;
}
}
});
System.out.println("排序后:" + stuList);
}
}
排序前:[5, 4, 6, 3, 7, 2, 8, 1, 9, 0]
排序后:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
排序前:[Student{id=1001, grade=60}, Student{id=1002, grade=100}, Student{id=1000, grade=60}]
排序后:[Student{id=1002, grade=100}, Student{id=1000, grade=60}, Student{id=1001, grade=60}]
排序前:[Student{id=1002, grade=100}, Student{id=1000, grade=60}, Student{id=1001, grade=60}]
排序后:[Student{id=1000, grade=60}, Student{id=1001, grade=60}, Student{id=1002, grade=100}]