版权声明:本文为博主原创文章,转载请注明出处:https://twocups.cn/index.php/2020/02/05/18/
有时我们需要对同一类型的对象进行多种不同方式的排序,而自然排序 Comparable 并不能实现。这里我们就需要重写比较器,可以让对象数组或集合以自定义的排序规则进行排序。
示例
给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。例如 [10, 2] 的输出为210,[3, 30, 34, 5, 9] 的输出为9534330。
这道题解法的关键就是排序,具体的规则为:数组中的非负整数(例如 x 和 y)两两进行比较,若x + y > y + x,则判定 x 的优先级比 y 高,且 x 在最终的整数里排在 y 的前面。
代码
import java.util.Arrays; import java.util.Comparator; class Test{ public String largestNumber(int[] nums) { Integer[] arr = new Integer[nums.length]; for(int i = 0; i < nums.length; i++) arr[i] = nums[i]; Arrays.sort(arr, new Comparator<Integer>(){ @Override public int compare(Integer o1, Integer o2){ String s1 = o1 + "" + o2; String s2 = o2 + "" + o1; return s2.compareTo(s1); } }); StringBuffer sb = new StringBuffer(); for(int x: arr) sb.append(x); String res = sb.toString(); return res.charAt(0) == '0' ? "0" : res; } }
代码中我们使用了数组的排序方法 sort(),并且重写了一个比较器 Comparator 来定义数组中元素在排序时两两之间的比较规则。如果是集合,同样也可以使用 Collections 的排序方法 sort()。有些人在使用这个方法的时候会遇到如下问题:
英文版: Error: java: no suitable method found for sort(char[],<anonymous java.util.Comparator<java.lang.Character>>) method java.util.Arrays.<T>sort(T[],java.util.Comparator<? super T>) is not applicable (inference variable T has incompatible bounds equality constraints: char upper bounds: java.lang.Character,java.lang.Object) method java.util.Arrays.<T>sort(T[],int,int,java.util.Comparator<? super T>) is not applicable (cannot infer type-variable(s) T (actual and formal argument lists differ in length)) 中文版: Error: java: 对于sort(char[],<匿名java.util.Comparator<java.lang.Character>>), 找不到合适的方法 方法 java.util.Arrays.<T>sort(T[],java.util.Comparator<? super T>)不适用 (推论变量 T 具有不兼容的限制范围 等式约束条件: char 上限: java.lang.Character,java.lang.Object) 方法 java.util.Arrays.<T>sort(T[],int,int,java.util.Comparator<? super T>)不适用 (无法推断类型变量 T (实际参数列表和形式参数列表长度不同))
原因是 public static void sort (T [] a,Comparator c) 是根据指定比较器引发的顺序对指定的对象数组进行排序,所以 sort() 方法的第一个参数 T [] a 中只能存放对象,而不能存放基本数据类的数据。如果将 char 类型的数组传入该方法,则会报出以上错误;如果传入的是 Character 类型的数组,则正常。
这里可能有人要问了,char 类型的数据和 Character 类型的数据不是会自动装箱和封箱吗,那为什么这里两者的数组不能通用呢?
通用不代表混用。char 在 Java 中属于八大基本数据类型,不需要实例化就能直接使用;而 Character 是 char 的封装类,需要实例化后才能用。一般来说,char 类型的数据和 Character 类型的数据会动态地进行自动封箱和装箱,来满足不同的需求,但是 char 类型的数组和 Character 类型的数组并不会自动转换啊,它们的本质是数组,只是存放了两种类型的数据而已。
所以如果之前得到的是 char 类型的数组,需要我们自己新建其封装类数组,并将 char 数组的元素全部装入其封装类数组中(这里将元素装入时才会自动封箱)。
其实,在特殊情况下还有更加方便的写法,我举两个例子。
// 将排序的参照要素从数组中的元素变成该元素的某个部分 int[] nums = new int[]{{2, 5}, {3, 7}, {1, 5}, {9, 1}}; Arrays.sort(nums , Comparator.comparingInt(a -> a[0])); // 改变排序所依照的两个元素的比较方式 String[] strs = new String[]{"aaa", "bbb"}; Arrays.sort(strs , (x, y) -> y.compareTo(x)); // 优先队列:由原来的升序排序,到现在的根据元素的time属性降序排序 PriorityQueue<Integer> priorityQueue = new PriorityQueue<>((a, b) -> (b.time - a.time));