在java中选择N个随机不同的int的高效方法?

时间:2015-01-26 14:23:48

标签: java random

我目前正在寻找最好的方法,因此在n个整数范围内选择x个唯一的整数。这就像多次执行Random.nextInt(range)一样,但它永远不应该选择两次相同的int。 如果它发生x > n,那么结果将只包含n个整数

我自己尝试这样做,而且我目前基于Fisher / Yates shuffle做了这个:

private static final Random R   = new Random();

public static int[] distinctRandoms(int nb, int max) {
    int[] all = new int[max];
    for (int i = 0; i < all.length; i++) {
        all[i] = i;
    }
    if (max <= nb) {
        return all;
    }
    int index;
    int[] result = new int[nb];

    for (int j = 0, k = all.length - 1; k > 0 && j < nb; k--, j++) {
        index = R.nextInt(k + 1);
        result[j] = all[index]; // save element
        all[index] = all[k]; // overwrite chosen with last element
    }
    return result;
}

它的工作和性能似乎很好,但我不禁想到仍然必须有一些更高性能的方式,并且我正在重新发明轮子。如果nb > (max / 2)(删除元素而不是选择元素),我考虑过以不同的方式做事,但由于你不能在java中截断数组,你仍然最终会复制你需要的所有元素。 如果nb = max-1

,此方法会花费很多

有没有内置的方法可以在java中有效地随机选择不同的int?

修改1:

高性能的意思是节省时间。我希望它快。我将主要使用小套的randoms。

编辑2:

我尝试使用shuffle,但由于所有额外的对象创建,它在时间上要贵得多。

public static Integer[] distinctRandoms2(int nb, int max) {
    ArrayList<Integer> all = new ArrayList<Integer>(max);
    for (int i = 0; i < max; i++) {
        all.add(i);
    }
    if (max <= nb) {
        return all.toArray(new Integer[max]);
    }
    Collections.shuffle(all);
    return all.subList(0, nb).toArray(new Integer[nb]);
}

4 个答案:

答案 0 :(得分:3)

您可以使用java.util.Collections课程中的shuffle方法。

只需创建从0x-1的整数列表,然后在其上调用shuffle方法并获取前nb个元素。

shuffle接近nb时,使用max方法有意义。因此,遵循成对参数会很好:

  • nb=70, max=100
  • nb=900, max=1000
  • nb=9000, max=10000

但不太适合:

  • nb=10, max=10^8
  • nb=100, max=10^9

将上述方法(使用shuffle)与其他答案中的Floyd算法结合起来是个好主意。算法的选择应基于比率nb/max。应谨慎选择边界比率。

答案 1 :(得分:3)

您可以使用Floyd的算法。如果要选择的元素数量小于其范围,则它比混洗更有效。

private static final Random random = new Random();

/**
 * Converts a set of Integer to an array of int.
 */
private static int[] setToArray(Set<Integer> aSet) {
    int[] result = new int[aSet.size()];
    int index = 0;
    for (int number : aSet) {
        result[index] = number;
        index++;
    }
    return result;
}

/**
 * Generates an array of min(count, maxValue) distinct random ints 
 * from [0, maxValue - 1] range.
 * @param count The number of elements to be generated.
 * @param maxValue The upper bound of the range(exclusively).
 */
public static int[] getDistinctRandomNumbers(int count, int maxValue) {
    Set<Integer> was = new HashSet<>();
    for (int i = Math.max(0, maxValue - count); i < maxValue; i++) {
        int curr = i == 0 ? 0 : random.nextInt(i);
        if (was.contains(curr))
            curr = i;
        was.add(curr);
    }
    return setToArray(was);
}

它具有O(count)时间和空间复杂度,其中count是应生成的不同整数的数量。

答案 2 :(得分:2)

这取决于PerformantRandom的含义。

如果您确实需要费用为O(1)或类似费用的内容,则可以使用Linear feedback shift registerLFSR。它使用前一个数字上的简单XOR运算生成一个随机数字序列(即统计随机但在理论上可预测),因此可能是最快的机制。

如果您想要任何n位数,这种方法最合适。通过丢弃超出所需范围的数量来限制数量范围可能会降低性能。

答案 3 :(得分:1)

如果通过&#34;小组的randoms&#34;你的意思是max很小,Collections#shuffle方法可能就像你能得到的一样好。

如果max可以是任意大,但nb很小,那么使用HashSet可能是您的最佳选择,尽管您会有一些装箱/取消装箱费用。如果您想避免这笔费用,可以尝试使用an IntHashSetHashSet的类似原始专业。