背景
Java的内置静态方法Arrays.sort()中,有一个方法是这样的:
static <T> void sort(T[] a, Comparator<? super T> c) ,
官方文档API对这个函数的描述如下图:
简单来说,这个方法输入参数有两个,数组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也没问题。