【问题标题】:Generate Random Numbers in Array [duplicate]在数组中生成随机数 [重复]
【发布时间】:2011-12-28 08:20:55
【问题描述】:

可能重复:
Unique random numbers in O(1)?

我是 Java 新手。我想从给定的集合中生成一组随机数,并且这些数字也不能重复。例如,可能的数字是[0,1,2,3],我想获取三个随机唯一数字存储在一个数组中。前任。 [0,2,1], [2,3,1], [0,3,2]

【问题讨论】:

  • 什么意思?对不起,我不明白
  • Thilo 的评论是作为投票的一部分自动生成的,以关闭此问题并将其链接到评论中的问题。这个问题已经被问及并得到了回答。你应该先搜索一下。

标签: java arrays algorithm random


【解决方案1】:

你需要一个 Fisher-Yates 洗牌。

这是一个非常有效的“从 m 中选择 n”解决方案,它为您提供了一个值的子集,其中 0 个重复的可能性(并且没有不必要的预先排序)。执行此操作的伪代码如下:

dim n[N]                  // gives n[0] through n[N-1]
for each i in 0..N-1:
    n[i] = i              // initialise them to their indexes

nsize = N                 // starting pool size
do N times:
    i = rnd(nsize)        // give a number between 0 and nsize-1
    print n[i]
    nsize = nsize - 1     // these two lines effectively remove the used number
    n[i] = n[nsize]

通过简单地从池中选择一个随机数(基于当前池大小),将其替换为该池中的顶部数字,然后减小池的大小,您可以获得一个随机数,而不必担心一个大预先交换的数量。

如果数字很大,这一点很重要,因为它不会引入不必要的启动延迟。

例如,检查以下基准检查,选择 10-from-10:

<------ n[] ------>
0 1 2 3 4 5 6 7 8 9  nsize  rnd(nsize)  output
-------------------  -----  ----------  ------
0 1 2 3 4 5 6 7 8 9     10           4       4
0 1 2 3 9 5 6 7 8        9           7       7
0 1 2 3 9 5 6 8          8           2       2
0 1 8 3 9 5 6            7           6       6
0 1 8 3 9 5              6           0       0
5 1 8 3 9                5           2       8
5 1 9 3                  4           1       1
5 3 9                    3           0       5
9 3                      2           1       3
9                        1           0       9

您可以看到池在减少,因为您总是用未使用的替换使用过的,因此您永远不会重复。


下面是一个小 Java 程序,展示了这一点:

import java.util.Random;

public class testprog {
    private int[] pool;           // The pool of numbers.
    private int size;             // The current "size".
    private Random rnd;           // A random number generator.

    // Constructor: just initilise the pool.

    public testprog (int sz) {
        pool = new int[sz];
        size = sz;
        rnd = new Random();
        for (int i = 0; i < size; i++) pool[i] = i;
    }

    // Get next random number in pool (or -1 if exhausted).

    public int next() {
        if (size < 1) return -1;
        int idx = rnd.nextInt(size--);
        int rval = pool[idx];
        pool[idx] = pool[size];
        return rval;
    }

    // Test program for the pool.

    public static void main(String[] args) {
        testprog tp = new testprog (10);
        for (int i = 0; i < 11; i++) System.out.println (tp.next());
    }
}

输出是(对于一个特定的运行):

3
5
1
0
6
4
9
2
8
7
-1

-1 只是为了向您展示当您用完列表时会发生什么。由于您已明确声明您不想要重复项,因此它会返回一个标记值。您还可以选择其他选项,例如引发异常或仅重新启动池。

【讨论】:

  • @BennettYoung 它是伪代码,抱歉,但您必须学习编程。不过这个算法是正确的。
  • 比“Java”好。这是对算法的解释,可以准确地得到你所要求的。下次要求“无需费力的复制和粘贴解决方案”。
  • @Bennett,所有程序语言在行业工作 30 年后都是相同的 :-) 该算法可以相对容易地翻译成其中任何一种——为了完整性,我提供了一个完整的 Java 版本,但你如果您首先了解它是如何工作的(使用铅笔和纸在脑海中“运行”它是一个很好的方法)然后自己实现它,那将是一个更好的程序员。
猜你喜欢
  • 2013-05-09
  • 2015-08-13
  • 2016-05-05
  • 2014-01-11
  • 2014-11-10
  • 2014-04-25
  • 1970-01-01
  • 2016-08-20
相关资源
最近更新 更多