当前位置:  开发笔记 > 编程语言 > 正文

在数组中生成随机数

如何解决《在数组中生成随机数》经验,为你挑选了1个好方法。

你需要一个Fisher-Yates shuffle.

这是一个非常有效的"选择从m×n个"的解决方案,向你值的子集与可能性重复的(并且没有不必要的前期排序).执行此操作的伪代码如下:

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]

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

如果数量很高,这很重要,因为它不会引入不必要的启动延迟.

例如,检查以下基准检查,选择10比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

您可以随时查看游泳池的减少情况,因为您总是将未使用的游泳池替换为未使用的游泳池,因此您永远不会重复游戏.


这是一个小程序,它显示了这个:

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是那里只是为了告诉你,当你该名单会发生什么.由于您已明确声明您不需要重复项,因此它会返回一个标记值.您还可以选择其他选项,例如抛出异常或只是重新启动池.



1> paxdiablo..:

你需要一个Fisher-Yates shuffle.

这是一个非常有效的"选择从m×n个"的解决方案,向你值的子集与可能性重复的(并且没有不必要的前期排序).执行此操作的伪代码如下:

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]

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

如果数量很高,这很重要,因为它不会引入不必要的启动延迟.

例如,检查以下基准检查,选择10比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

您可以随时查看游泳池的减少情况,因为您总是将未使用的游泳池替换为未使用的游泳池,因此您永远不会重复游戏.


这是一个小程序,它显示了这个:

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,所有程序语言在业界三十年后都是相同的:-)这个算法可以相对容易地翻译成任何一个 - 我提供了一个完整的Java版本,但如果你是一个更好的程序员首先要了解它是如何起作用的(使用铅笔和纸张在头脑中"运行"是一种很好的方法)然后自己实现它.
推荐阅读
LEEstarmmmmm
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有