我最近遇到了一个表面看起来不正确的比较器。但是,我一直无法得到一个输入,导致比较器产生错误的结果。
如果o1< = o2,则错误地将值视为相等,如果o1>则错误地将值返回1 O 2。
我尝试在下面尽可能地简化场景。任何人都可以:
我已经尝试了很多,我正在扯皮!
package comparator;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class BadComparator implements Comparator<Integer>
{
public int compare(Integer o1, Integer o2)
{
// Generally Accepted implementation
//return o1 - o2;
// Incorrect(?) Implementation
return (o2 < o1) ? 1 : 0;
}
public static void main(String[] args)
{
List<Integer> intList = Arrays.asList(10, 9, 8, 1, 2, 3, 7, 4, 5, 6);
Collections.sort(intList, new BadComparator());
System.out.println(intList);
}
}
答案 0 :(得分:7)
它对我不起作用。它产生的输出为:
[10, 9, 8, 1, 2, 3, 7, 4, 5, 6]
(与输入订单相同)。但这并不能保证......我怀疑它恰好选择了已经按正确顺序排列的元素,或者它决定它们“相等”并让它们独自存在。
请注意,o1 - o2
也已损坏...请考虑o1 = Integer.MIN_VALUE
和o2 = 1
...您可以通过转换为{{1}来解决此问题当然,首先是价值观。
更自然的实现是
long
或:
return o1.compareTo(o2);
答案 1 :(得分:3)
它是偶然的;它的工作原理取决于Collections.sort()
的实现细节。由于比较器没有根据其合同执行它应该执行的操作,因此您无法确定它是否会继续在其他JVM实现或甚至其他版本的Oracle JVM上工作。
尝试找出工作原理并没有多大意义。
答案 2 :(得分:3)
Collections.sort实现为mergesort。查看来源,所有比较条件都是>0
或<=0
,偶然地将负面情况视为相同的情况。不同的排序实现可能会失败。
根据jbellis的评论,“它不是”只是运气,“但是 - Collections.sort保证是”稳定的“,这意味着相等的元素必须在排序后的相对相对顺序。我我不确定用这个比较器来实现一个稳定的排序实现是不可能的,但是我不能想到我的头脑。“
private static void mergeSort(Object[] src,
Object[] dest,
int low, int high, int off,
Comparator c) {
int length = high - low;
// Insertion sort on smallest arrays
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
// Recursively sort halves of dest into src
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >> 1;
mergeSort(dest, src, low, mid, -off, c);
mergeSort(dest, src, mid, high, -off, c);
// If list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
if (c.compare(src[mid-1], src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
// Merge sorted halves (now in src) into dest
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
答案 3 :(得分:1)
这显然是一个不正确的Comparator
实施。例如,Javadoc说:
实施者必须确保这一点 sgn(比较(x,y))== -sgn(比较(y, x))所有x和y。
在这种情况下显然不正确,因为它可以返回1而不是-1。
我相信它在排序时不会引起问题的原因是,使用标准比较器,如果compare方法返回-1或0,则列表中的两个元素处于可接受的顺序,但如果使用标准比较器,则必须交换它们它返回1.因此,至少对于某些排序算法,正确指示第二个参数是否大于第一个参数必须足够。