为什么播种此Random对象会导致意外的Comparator行为?

时间:2014-03-23 04:14:02

标签: java random comparator

我是一名自学有关比较器的学生,我遇到了一些我理解困难的奇怪行为。我试图使用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]

有人可以帮我理解这种行为吗?

我明白这是可怕的代码。这些只是玩具示例,可以帮助我熟悉比较器的机制。无论如何,我对结果行为更感兴趣。

3 个答案:

答案 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。)