我是一名自学有关比较器的学生,我遇到了一些我理解困难的奇怪行为。我试图使用Arrays.sort和Random对象来重新排列数组,但是当我为Random对象播种时,shuffle会反转数组或什么都不做。不播种Random对象会导致它按预期被洗牌。
没有种子:
Integer[] integers = new Integer[]{1, 2, 3, 4, 5, 6};
Arrays.sort(integers, new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return new Random().nextInt();
}
});
>>> [4, 3, 5, 2, 1, 6]
种子:
Integer[] integers = new Integer[]{1, 2, 3, 4, 5, 6};
Arrays.sort(integers, new Comparator<T>() {
@Override
public int compare(T o1, T o2) {
return new Random(System.currentTimeMillis()).nextInt();
}
});
>>> [1, 2, 3, 4, 5, 6] or [6, 5, 4, 3, 2, 1]
有人可以帮我理解这种行为吗?
我明白这是可怕的代码。这些只是玩具示例,可以帮助我熟悉比较器的机制。无论如何,我对结果行为更感兴趣。
答案 0 :(得分:3)
种子控制您生成的随机数流。如果你使用相同的种子种子,你每次都会获得相同的序列。你每次都使用相同的号码进行种子播放(因为它甚至不需要1ms进行排序),所以nextInt()将始终返回相同的值。因此它将始终返回相同的类型。由于您的数据已排序,因此会使其保持相同的顺序。
如果要正确播种,请创建一次Random对象,然后调用它,而不是每次都使用相同的种子重新创建。
答案 1 :(得分:2)
由于代码运行速度很快,因此创建的大多数Random对象将获得相同的种子。
例如,你可以在比较器中输入一个简短的Thread.sleep(10)
。或者你可以运行:
for (int i = 0; i < 7; i++) {
System.out.println("" + new Random(System.currentTimeMillis()).nextInt());
}
你明白为什么这是可怕的代码,对吧?您只能创建一个Random对象,然后在Comparator中使用相同的对象,对吧?
答案 2 :(得分:0)
即使您只使用一个Random对象,使用随机Comparator仍会出现意外行为。来自documentation from Comparator。
实现者必须确保sgn(compare(x,y))== -sgn(比较(y, x))所有x和y。
如果不遵循该实现要求,您将获得未定义的行为。 您可以在此处查看生成的随机播放内容的可视化:http://bost.ocks.org/mike/shuffle/compare.html
(注意:那里的shuffle使用Javascript而不是Java,但问题也适用于Java。)