Arrays.sort() Collections.sort() 自定义排序


Java的JDK中提供了强大的接口,其中关于自定义排序的方法主要有如下几类:

Arrays中sort方法

sort方法有很多的重载,实现了不同数据类型的排序和自定义排序;

基本数据类型的排序

基本数据类型的排序直接使用相应的方法sort(int[] a),支持的数据类型数组包括:

  1. char[] a;
  2. byte[] a;
  3. short[] a;
  4. int[] a;
  5. long[] a;
  6. float[] a;
  7. 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方法;
主要是以下几种:

  1. 基本类型的包装类,其已经实现了Comparable接口;
  2. JDK中实现了Comparable接口的类,如String;
  3. 自定义类并实现接口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接口下的各类使用的;包括两种:

  1. 类已经实现了Comparable接口:public static <T extends Comparable<? super T>> void sort(List list)
  2. 自定义比较器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}]

Comparable和Comparator解析见另一篇文章

Comparable和Comparator解析

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值