Java使用自定义Comparator按因数个数排序不生效问题
问题根因
排序失效是因为自定义的Comparator不符合Java接口的返回契约,Arrays.sort使用的比较器要求必须遵循以下返回规则:
- 当第一个参数应该排在第二个参数前面时,返回负整数
- 当两个参数优先级相等时,返回0
- 当第一个参数应该排在第二个参数后面时,返回正整数
原代码的比较器存在两个致命问题:
- 完全没有返回负整数的逻辑分支:当
fact_a > fact_b、以及因数个数相等但A1 > B的场景下,代码直接返回0,排序算法会判定两个元素优先级完全相等,不需要交换位置 - 逻辑分支覆盖不全:仅处理了因数更少、同因数下数值更小两种需要后置的场景,其余所有场景都被判定为元素相等,最终排序算法不会调整任何元素顺序,输出和原数组完全一致。
修复方案
补全比较器的所有判断分支,严格遵循返回值契约即可。如果要实现「按因数个数降序排序,因数个数相同时按数值降序排序」的逻辑(和原代码预期逻辑一致),修复后的完整代码如下:
public void solve(){ Integer[] A = new Integer[]{3,9,4,6,12,10,7}; System.out.println(Arrays.toString(A)); Arrays.sort(A, (A1, B) -> { int fact_a = calcFactors(A1); int fact_b = calcFactors(B); // 优先按因数个数降序排列 if (fact_a != fact_b) { return fact_b - fact_a; } // 因数个数相同时,按数值降序排列 return B - A1; }); System.out.println(Arrays.toString(A)); } public int calcFactors(int A){ int count = 0; int sqrt = (int)Math.sqrt(A); for(int i =1;i<=sqrt;i++){ if(A%i == 0) count+=2; } if(sqrt*sqrt == A) count--; return count; }
修复后运行代码,输出结果为[12, 10, 6, 9, 4, 7, 3],符合排序预期。
注:如果需要按因数个数升序、数值升序排列,只需要把比较器的返回值调整为
fact_a - fact_b和A1 - B即可。
内容的提问来源于stack exchange,提问作者Ulhas Ch
相关产品推荐
相关产品推荐

