背景

Java的内置静态方法Arrays.sort()中,有一个方法是这样的:

static <T> void sort(T[] a, Comparator<? super T> c) ,


java 重写 comparator java 重写sort_java 重写 comparator

官方文档API对这个函数的描述如下图:

java 重写 comparator java 重写sort_java 重写 comparator_02

 简单来说,这个方法输入参数有两个,数组a和比较器c。通过自己定义比较器c,实现对sort排序规则的改变。因为sort()默认是对a进行升序(从小到大),若你想对a进行降序(从大到小),就需要改写sort()的比较器c了。

对整型数组a实现降序的示例代码如下:

Arrays.sort(a,new Comparator<>(){
		public int compare(int a, int b){
				return b-a;
		}
});

或者用Lambda表达式进行改写,更简洁了:

Arrays.sort(arr, (a,b)->b-a );

怎么理解

那怎么理解呢,为什么改成这样就能实现数组的降序呢?是这样的:

1 Java内置的静态方法Arrays.sort()默认是将数组调整为升序,它的代码中实现了Compareable接口的compare(a,b)方法,该方法用于比较两个元素的大小。

2 而它实现的compare(a,b)方法默认是这样的:若a>b,输出正数;若a<b,输出负数;若a=b,输出0。它的方法体实际代码为:return a-b;

3.1 若我们将compare(a,b)方法重写,相比原先默认的,将它的输出值的正负符号取反;

3.2 对于内置Arrays.sort()的除compare(a,b)方法外的其他代码保留不变。这样改写后调用sort,出来的结果将相反,即实现数组降序。

4 即将compare(a,b)方法重写为这样:若a>b,输出负数;若a<b,输出正数;若a=b,输出0。故,方法体要改写成这样的代码:return -(a-b);(即return b-a;)

总结提炼

对于封装类整型数组Integer[] n,Arrays.sort(n),可将数组n内的元素调整为升序,或:       [1]

Arrays.sort(n, (x1,x2)->x1-x2 );   // 效果等同于 Arrays.sort(n);

降序写法1:(不推荐)

若想调整为降序,需要改写为:

Arrays.sort(n, (x1,x2)->x2-x1 ); // 刷leetcode时发现这种写法有点小问题,推荐下方的写法2。

在改写compare(a,b)方法时,其实就是要选择返回a-b还是b-a,可以这样理解着改写:

假设数组的前两个元素从左到右分别为a和b,且a>b(即数组初始顺序为降序),

若你想调用sort后,顺序改为升序,则让其输出正数,返回a-b;若你想用sort后,顺序不变仍保持为降序,则让输出负数,返回b-a。

降序写法2:(推荐)

降序写法1中,假设x2为Integer.MIN_VALUE,x1为正数时,计算时x1-x2时会溢出,返回有误。

推荐以下写法,将数组n调整为降序:

Arrays.sort(n, (x1,x2)->Integer.compare(x2,x1) );

这种写法下,对比地,将数组n调整为升序的代码为:

Arrays.sort(n, (x1,x2)->Integer.compare(x1,x2) );  // 效果等同于 Arrays.sort(n);

显然,这种写法更好记、更好区分了。

拓展-二维数组排序

对于二维数组int[][] n,比如n的内容如下,     [2]

[7,0]
[4,4]
[7,1]
[5,0]
[6,1]
[5,2]

若想实现数组n按第0列降序第1列升序,即sort后n的内容如下,

[7,0]
[7,1]
[6,1]
[5,0]
[5,2]
[4,4]

第0列降序、第1列升序:若第0列的元素不等,按第0列降序输出;若第0列的元素相等,按第1列升序输出。

sort需要这样调用:

Arrays.sort(n,(x1,x2)->{
    if (x1[0] != x2[0]){
        return x2[0]-x1[0];
    }else {
        return x1[1]-x2[1];
    }
});

// 或:
Arrays.sort(people, (x1,x2)-> x1[0]!=x2[0]? x2[0]-x1[0]:x1[1]-x2[1] );

// 或如下写法。推荐这种。
Arrays.sort(people, (x1,x2)-> x1[0]!=x2[0]? Integer.compare(x2[0],x1[0]): Integer.compare(x1[1],x2[1]) );

注意:

[1]句中的Integer[] n,不能是int[] n。否则无法运行,提示以下错误。

java: 对于sort(int[],(x1,x2)->([...], x1)), 找不到合适的方法
    方法 java.util.Arrays.<T>sort(T[],java.util.Comparator<? super T>)不适用
      (推论变量 T 具有不兼容的上限
        等式约束条件:int
        下限:java.lang.Object)
    方法 java.util.Arrays.<T>sort(T[],int,int,java.util.Comparator<? super T>)不适用
      (无法推断类型变量 T
        (实际参数列表和形式参数列表长度不同))

也就是说,需要重写Java的Arrays.sort()的比较器Comparator时,传入的数组必须是封装类型的对象数组T[]。

[2]句中int[][] n倒是可以正常运行,当然Integer[][] n也没问题。