创建无重复的随机数


87

在这种情况下,MAX仅为5,因此我可以一张一张地检查重复项,但是如何以更简单的方式进行检查呢?例如,如果MAX的值为20,该怎么办?谢谢。

int MAX = 5;

for (i = 1 , i <= MAX; i++)
{
        drawNum[1] = (int)(Math.random()*MAX)+1;

        while (drawNum[2] == drawNum[1])
        {
             drawNum[2] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[3] == drawNum[1]) || (drawNum[3] == drawNum[2]) )
        {
             drawNum[3] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[4] == drawNum[1]) || (drawNum[4] == drawNum[2]) || (drawNum[4] == drawNum[3]) )
        {
             drawNum[4] = (int)(Math.random()*MAX)+1;
        }
        while ((drawNum[5] == drawNum[1]) ||
               (drawNum[5] == drawNum[2]) ||
               (drawNum[5] == drawNum[3]) ||
               (drawNum[5] == drawNum[4]) )
        {
             drawNum[5] = (int)(Math.random()*MAX)+1;
        }

}

3
许多(伪)随机数生成器不会重复其完整的“周期”。当然,问题在于它们的整个“周期”是数十亿或数万亿的价值,而它们产生的价值可能是这些数十亿或数万亿的价值中的任何一种。从理论上讲,您可以生成一个随机数生成器,其“周期”为5或10或任何其他值,但这可能比其价值更大。
热舔

1
同样,不重复的随机数生成器甚至是“较小”的随机数:如果MAX = 5并且您读取了3个数字,则可以以50%的概率猜测下一个,如果您读取4个数字,则可以知道100%的下一个当然!
icza 2014年

回答了重复的问题在这里
阿莱克斯- GlassEditor.com


Answers:


149

最简单的方法是创建一个可能数字的列表(1..20或任何数字),然后用对其进行洗牌Collections.shuffle。然后,只需考虑您想要的许多元素。如果您的范围最终等于您需要的元素数量(例如,用于洗牌的卡片),则这非常好。

如果您想(说)1..10,000范围内的10个随机元素,那么效果就不太好-您最终会不必要地进行大量工作。到那时,最好保留到目前为止已生成的一组值,并保持循环生成数字,直到下一个不存在为止:

if (max < numbersNeeded)
{
    throw new IllegalArgumentException("Can't ask for more numbers than are available");
}
Random rng = new Random(); // Ideally just create one instance globally
// Note: use LinkedHashSet to maintain insertion order
Set<Integer> generated = new LinkedHashSet<Integer>();
while (generated.size() < numbersNeeded)
{
    Integer next = rng.nextInt(max) + 1;
    // As we're adding to a set, this will automatically do a containment check
    generated.add(next);
}

不过,请谨慎选择设置-我非常有意地使用LinkedHashSet它,因为它会保持插入顺序,我们在这里关心它。

另一个选择是通过每次减小范围并补偿现有值来始终取得进展。因此,举例来说,假设您要使用0..9范围内的3个值。在第一次迭代中,您将生成0..9范围内的任何数字-假设您生成了4。

在第二次迭代中,您将生成一个范围为0..8的数字。如果生成的数字小于4,则应按原样保留它;否则,将其添加一个。这样得到的结果范围是0..9(不带4)。假设我们以这种方式得到7。

在第三次迭代中,您将生成一个范围为0..7的数字。如果生成的数字小于4,则应保持原样。如果是4或5,则要加一个。如果是6或7,则要加两个。这样,结果范围是0..9,没有4或6。


生成可能值的数组,随机选择一个(随机数mod数组大小),删除(并保存)选定的数字,然后重复。
热舔

或使用具有完整周期的随机生成器(基于素数的生成器可以使用较小的素数-相应的较小周期),并将值超出范围。
Paul de Vrieze,2011年

“还有另一个选择是始终取得进步”是WAAAAY更好的解决方案。请编辑以反映。并感谢您的出色回答。
user123321 2012年

1
@musselwhizzle:将尝试尽快找到时间。我不确定“ WAAAY更好”,尽管它会更有效率,但“明显正确”的情况将大大减少。为了获得可读性,我经常很乐意牺牲性能。
乔恩·斯基特

@Deepthi:根据问题,OP想要的最大数量。
乔恩·斯基特

19

这是我会做的

import java.util.ArrayList;
import java.util.Random;

public class Test {
    public static void main(String[] args) {
        int size = 20;

        ArrayList<Integer> list = new ArrayList<Integer>(size);
        for(int i = 1; i <= size; i++) {
            list.add(i);
        }

        Random rand = new Random();
        while(list.size() > 0) {
            int index = rand.nextInt(list.size());
            System.out.println("Selected: "+list.remove(index));
        }
    }
}

正如尊敬的Skeet先生所指出的:
如果n是您要选择的随机选择的数字的数量,而N是可供选择的数字的总样本空间:

  1. 如果n << N,则应该只存储您选择的数字并检查列表以查看其中是否包含所选数字。
  2. 如果n〜 = N,您可能应该使用我的方法,方法是填充一个包含整个样本空间的列表,然后在选择它们时从中删除数字。

list应该是LinkedList,从arraylist中删除随机索引效率很低
Riccardo Casatta

@RiccardoCasatta你有断言的来源吗?我也无法想象遍历链表也很有效。另请参阅:stackoverflow.com/a/6103075/79450
Catchwa,

我测试了一下,您说的对,我应该删除我的评论吗?
里卡多·卡萨塔

@RiccardoCasatta其他人可能会发现我们的来回有用
Catchwa

13
//random numbers are 0,1,2,3 
ArrayList<Integer> numbers = new ArrayList<Integer>();   
Random randomGenerator = new Random();
while (numbers.size() < 4) {

    int random = randomGenerator .nextInt(4);
    if (!numbers.contains(random)) {
        numbers.add(random);
    }
}

对于大量用户而言,这将具有可怕的性能。ArrayList.contains正在遍历列表。更加干净的是使用Set,而无需检查它是否包含,只需添加即可,性能会更好。
kfox

5

还有另一种使用LFSR处理“随机”有序数字的方法,请看一下:

http://en.wikipedia.org/wiki/Linear_feedback_shift_register

使用此技术,您可以按索引获得有序的随机数,并确保值不重复。

但是这些不是TRUE随机数,因为随机生成是确定性的。

但是根据您的情况,可以使用此技术来减少使用混洗时生成随机数的处理量。

这是Java中的LFSR算法,(我把它放在不记得的地方):

public final class LFSR {
    private static final int M = 15;

    // hard-coded for 15-bits
    private static final int[] TAPS = {14, 15};

    private final boolean[] bits = new boolean[M + 1];

    public LFSR() {
        this((int)System.currentTimeMillis());
    }

    public LFSR(int seed) {
        for(int i = 0; i < M; i++) {
            bits[i] = (((1 << i) & seed) >>> i) == 1;
        }
    }

    /* generate a random int uniformly on the interval [-2^31 + 1, 2^31 - 1] */
    public short nextShort() {
        //printBits();

        // calculate the integer value from the registers
        short next = 0;
        for(int i = 0; i < M; i++) {
            next |= (bits[i] ? 1 : 0) << i;
        }

        // allow for zero without allowing for -2^31
        if (next < 0) next++;

        // calculate the last register from all the preceding
        bits[M] = false;
        for(int i = 0; i < TAPS.length; i++) {
            bits[M] ^= bits[M - TAPS[i]];
        }

        // shift all the registers
        for(int i = 0; i < M; i++) {
            bits[i] = bits[i + 1];
        }

        return next;
    }

    /** returns random double uniformly over [0, 1) */
    public double nextDouble() {
        return ((nextShort() / (Integer.MAX_VALUE + 1.0)) + 1.0) / 2.0;
    }

    /** returns random boolean */
    public boolean nextBoolean() {
        return nextShort() >= 0;
    }

    public void printBits() {
        System.out.print(bits[M] ? 1 : 0);
        System.out.print(" -> ");
        for(int i = M - 1; i >= 0; i--) {
            System.out.print(bits[i] ? 1 : 0);
        }
        System.out.println();
    }


    public static void main(String[] args) {
        LFSR rng = new LFSR();
        Vector<Short> vec = new Vector<Short>();
        for(int i = 0; i <= 32766; i++) {
            short next = rng.nextShort();
            // just testing/asserting to make 
            // sure the number doesn't repeat on a given list
            if (vec.contains(next))
                throw new RuntimeException("Index repeat: " + i);
            vec.add(next);
            System.out.println(next);
        }
    }
}

4

另一种方法,它允许您指定多少个号码想sizeminmax值返回的数字

public static int getRandomInt(int min, int max) {
    Random random = new Random();

    return random.nextInt((max - min) + 1) + min;
}

public static ArrayList<Integer> getRandomNonRepeatingIntegers(int size, int min,
        int max) {
    ArrayList<Integer> numbers = new ArrayList<Integer>();

    while (numbers.size() < size) {
        int random = getRandomInt(min, max);

        if (!numbers.contains(random)) {
            numbers.add(random);
        }
    }

    return numbers;
}

要使用它,返回0到25之间的7个数字。

    ArrayList<Integer> list = getRandomNonRepeatingIntegers(7, 0, 25);
    for (int i = 0; i < list.size(); i++) {
        System.out.println("" + list.get(i));
    }

4

这在以下方面会简单得多java-8

Stream.generate(new Random()::ints)
            .distinct()
            .limit(16) // whatever limit you might need
            .toArray(Integer[]::new);

3

此伪代码说明了拥有非重复随机数的最有效,基本的方法。不需要嵌套循环或哈希查找:

// get 5 unique random numbers, possible values 0 - 19
// (assume desired number of selections < number of choices)

const int POOL_SIZE = 20;
const int VAL_COUNT = 5;

declare Array mapping[POOL_SIZE];
declare Array results[VAL_COUNT];

declare i int;
declare r int;
declare max_rand int;

// create mapping array
for (i=0; i<POOL_SIZE; i++) {
   mapping[i] = i;
}

max_rand = POOL_SIZE-1;  // start loop searching for maximum value (19)

for (i=0; i<VAL_COUNT; i++) {
    r = Random(0, max_rand); // get random number
    results[i] = mapping[r]; // grab number from map array
    mapping[r] = max_rand;  // place item past range at selected location

    max_rand = max_rand - 1;  // reduce random scope by 1
}

假设第一次迭代生成随机数3开始(从0到19)。这将使结果[0] =映射[3],即值3。然后将映射[3]分配给19。

在下一次迭代中,随机数为5(从0到18)。这将使结果[1] =映射[5],即值为5。然后将映射[5]分配给18。

现在,假设下一次迭代再次选择3(从0到17)。将为result [2]分配mapping [3]的值,但是现在,该值不是3,而是19。

即使您连续5次获得相同的号码,所有号码也会保持相同的保护。例如,如果随机数生成器连续五次为您提供0,则结果将是:[0,19,18,17,16]。

您永远不会两次获得相同的号码。


我怀疑这听起来是随机的。是否通过标准随机性测试?它似乎将数字集中在频谱的末端。
tucuxi

这是一个基本情况。池为{a,b,c}。我们需要2个非重复元素。遵循以下算法,这是我们可以绘制的组合及其结果:0,0:a,c 0,1:a,b 1,0:b,a 1,1:b,c 2,0:c,a 2, 1:c,b得分:a-4,b-4,c-4
blackcatweb

3

生成序列的所有索引通常不是一个好主意,因为这可能会花费很多时间,尤其是在要选择的数字与数字的比率MAX很低的情况下(复杂度由决定O(MAX))。如果要选择的数字与MAX一个数字的比率接近一个,这将变得更糟,因为从所有序列中删除选择的索引也变得很昂贵(我们接近O(MAX^2/2))。但是对于少量数字,此方法通常效果很好,并且不太容易出错。

使用集合过滤生成的索引也是一个坏主意,因为花费一些时间将索引插入序列中,并且由于可以绘制相同的随机数次而不能保证进度(但是对于足够大的情况,MAX这不太可能)。这可能接近复杂性
O(k n log^2(n)/2),忽略重复项并假设该集合使用树进行有效查找(但k分配树节点的成本相当高,并且可能不得不重新平衡)。

另一种选择是从一开始就唯一地生成随机值,以确保取得进展。这意味着在第一轮中,将[0, MAX]生成一个随机索引:

items i0 i1 i2 i3 i4 i5 i6 (total 7 items)
idx 0       ^^             (index 2)

在第二轮中,仅[0, MAX - 1]生成(因为已经选择了一项):

items i0 i1    i3 i4 i5 i6 (total 6 items)
idx 1          ^^          (index 2 out of these 6, but 3 out of the original 7)

然后需要调整索引的值:如果第二个索引落在序列的后半部分(在第一个索引之后),则需要对其进行递增以解决间隔问题。我们可以将其实现为循环,从而允许我们选择任意数量的唯一项。

对于短序列,这是相当快的O(n^2/2)算法:

void RandomUniqueSequence(std::vector<int> &rand_num,
    const size_t n_select_num, const size_t n_item_num)
{
    assert(n_select_num <= n_item_num);

    rand_num.clear(); // !!

    // b1: 3187.000 msec (the fastest)
    // b2: 3734.000 msec
    for(size_t i = 0; i < n_select_num; ++ i) {
        int n = n_Rand(n_item_num - i - 1);
        // get a random number

        size_t n_where = i;
        for(size_t j = 0; j < i; ++ j) {
            if(n + j < rand_num[j]) {
                n_where = j;
                break;
            }
        }
        // see where it should be inserted

        rand_num.insert(rand_num.begin() + n_where, 1, n + n_where);
        // insert it in the list, maintain a sorted sequence
    }
    // tier 1 - use comparison with offset instead of increment
}

n_select_num你的5和n_number_num你的哪儿MAX?将n_Rand(x)在返回随机整数[0, x](含)。如果通过使用二进制搜索找到插入点来选择很多项目(例如不是5个而是500个),则可以使速度更快一些。为此,我们需要确保满足要求。

我们会做的比较二进制搜索n + j < rand_num[j]是一样的
n < rand_num[j] - j。我们需要证明它rand_num[j] - j仍然是有序列的有序列rand_num[j]。幸运的是,这很容易显示,因为原件的两个元素之间的最小距离rand_num是1(生成的数字是唯一的,因此始终至少存在1的差异)​​。同时,如果我们j从所有元素中减去索引
rand_num[j],则索引之间的差异恰好为1。因此,在“最差”的情况下,我们得到一个恒定的序列-但从不减少。因此可以使用二进制搜索,产生O(n log(n))算法:

struct TNeedle { // in the comparison operator we need to make clear which argument is the needle and which is already in the list; we do that using the type system.
    int n;

    TNeedle(int _n)
        :n(_n)
    {}
};

class CCompareWithOffset { // custom comparison "n < rand_num[j] - j"
protected:
    std::vector<int>::iterator m_p_begin_it;

public:
    CCompareWithOffset(std::vector<int>::iterator p_begin_it)
        :m_p_begin_it(p_begin_it)
    {}

    bool operator ()(const int &r_value, TNeedle n) const
    {
        size_t n_index = &r_value - &*m_p_begin_it;
        // calculate index in the array

        return r_value < n.n + n_index; // or r_value - n_index < n.n
    }

    bool operator ()(TNeedle n, const int &r_value) const
    {
        size_t n_index = &r_value - &*m_p_begin_it;
        // calculate index in the array

        return n.n + n_index < r_value; // or n.n < r_value - n_index
    }
};

最后:

void RandomUniqueSequence(std::vector<int> &rand_num,
    const size_t n_select_num, const size_t n_item_num)
{
    assert(n_select_num <= n_item_num);

    rand_num.clear(); // !!

    // b1: 3578.000 msec
    // b2: 1703.000 msec (the fastest)
    for(size_t i = 0; i < n_select_num; ++ i) {
        int n = n_Rand(n_item_num - i - 1);
        // get a random number

        std::vector<int>::iterator p_where_it = std::upper_bound(rand_num.begin(), rand_num.end(),
            TNeedle(n), CCompareWithOffset(rand_num.begin()));
        // see where it should be inserted

        rand_num.insert(p_where_it, 1, n + p_where_it - rand_num.begin());
        // insert it in the list, maintain a sorted sequence
    }
    // tier 4 - use binary search
}

我已经在三个基准测试中对此进行了测试。首先,从7个项目中选择3个数字,并在10,000次运行中累积所选项目的直方图:

4265 4229 4351 4267 4267 4364 4257

这表明,这7个项目中的每一个都大约选择了相同的次数,并且没有明显的由算法引起的偏差。还检查所有序列的正确性(内容唯一性)。

第二个基准测试涉及从5000个项目中选择7个数字。该算法的多个版本的时间累计超过10,000,000次。结果在代码的注释中表示为b1。该算法的简单版本稍快一些。

第三个基准测试涉及从5000个项目中选择700个数字。再次累积了该算法的多个版本的时间,这次运行了10,000多次。结果在代码的注释中表示为b2。现在,该算法的二进制搜索版本比简单的算法快两倍以上。

第二种方法开始在我的机器上选择超过cca 75个项目时变得更快(请注意,这两种算法的复杂性都不取决于项目的数量MAX)。

值得一提的是,上述算法以升序生成随机数。但是,添加另一个数组将按其生成的顺序将数字保存起来很简单,然后将其返回(可以忽略不计的额外费用O(n))。不必对输出进行混洗:那会慢得多。

请注意,源代码是C ++,我的计算机上没有Java,但是概念应该很清楚。

编辑

出于娱乐目的,我还实现了一种生成带有所有索引的列表,
0 .. MAX随机选择它们并将其从列表中删除以确保唯一性的方法。由于我选择了很高的值MAX(5000),因此性能是灾难性的:

// b1: 519515.000 msec
// b2: 20312.000 msec
std::vector<int> all_numbers(n_item_num);
std::iota(all_numbers.begin(), all_numbers.end(), 0);
// generate all the numbers

for(size_t i = 0; i < n_number_num; ++ i) {
    assert(all_numbers.size() == n_item_num - i);
    int n = n_Rand(n_item_num - i - 1);
    // get a random number

    rand_num.push_back(all_numbers[n]); // put it in the output list
    all_numbers.erase(all_numbers.begin() + n); // erase it from the input
}
// generate random numbers

我还用set(一个C ++集合)实现了该方法,该方法实际上在基准测试中排名第二b2,仅比使用二进制搜索的方法慢约50%。这是可以理解的,因为set使用了二叉树,其插入成本类似于二叉搜索。唯一的不同是获得重复项目的机会,这会减慢进度。

// b1: 20250.000 msec
// b2: 2296.000 msec
std::set<int> numbers;
while(numbers.size() < n_number_num)
    numbers.insert(n_Rand(n_item_num - 1)); // might have duplicates here
// generate unique random numbers

rand_num.resize(numbers.size());
std::copy(numbers.begin(), numbers.end(), rand_num.begin());
// copy the numbers from a set to a vector

完整的源代码在这里


2

您可以使用实现Set接口(API)的类之一,然后使用Set.add()插入生成的每个数字。

如果返回值为false,则表示该号码已经生成过。


2

不用执行所有这些操作LinkedHashSet,而是通过Math.random()函数创建对象并为其随机编号....如果发生任何重复的条目,LinkedHashSet对象将不会将该数字添加到其列表中...因为在此Collection类中,不允许重复值..最后,您会得到一个没有重复值的随机数列表..:D


2

您的问题似乎减少了从n个元素的集合中随机选择k个元素。因此,Collections.shuffle答案是正确的,但指出效率低下:其O(n)。

Wikipedia:当数组已存在时, Fisher–Yates混洗具有O(k)版本。在您的情况下,没有元素数组,因此创建元素数组可能会非常昂贵,例如,如果max是10000000而不是20。

随机播放算法涉及初始化大小为n的数组,其中每个元素均等于其索引,从k个随机数中选取一个最大范围小于先前范围的范围内的每个数字,然后向数组末尾交换元素。

您可以使用哈希表在O(k)时间内执行相同的操作,尽管我承认这样做有点痛苦。请注意,这仅在k远小于n时才值得。(即k〜lg(n)左右),否则应直接使用随机播放。

您将使用哈希映射作为随机播放算法中后备数组的有效表示。数组中与其索引相等的任何元素都不需要出现在映射中。这使您可以在恒定时间内表示大小为n的数组,而无需花费任何时间对其进行初始化。

  1. 选择k个随机数:第一个在0到n-1之间,第二个在0到n-2之间,第三个0到n-3之间,依此类推,直到nk。

  2. 将您的随机数视为一组交换。第一个随机索引交换到最终位置。第二个随机索引交换到倒数第二个位置。但是,不是对后备数组进行操作,而是对哈希表进行处理。您的哈希图将存储所有位置不正确的项目。

int getValue(i) { if (map.contains(i)) return map[i]; return i; } void setValue(i, val) { if (i == val) map.remove(i); else map[i] = val; } int[] chooseK(int n, int k) { for (int i = 0; i < k; i++) { int randomIndex = nextRandom(0, n - i); //(n - i is exclusive) int desiredIndex = n-i-1; int valAtRandom = getValue(randomIndex); int valAtDesired = getValue(desiredIndex); setValue(desiredIndex, valAtRandom); setValue(randomIndex, valAtDesired); } int[] output = new int[k]; for (int i = 0; i < k; i++) { output[i] = (getValue(n-i-1)); } return output; }


creating the array of elements could be very expensive-为什么创建数组比改组更昂贵?我认为在这一点上绝对没有理由感到悲观:-)
Wolf

1

以下代码创建之前未生成的[1,m]之间的序列随机数。

public class NewClass {

    public List<Integer> keys = new ArrayList<Integer>();

    public int rand(int m) {
        int n = (int) (Math.random() * m + 1);
        if (!keys.contains(n)) {
            keys.add(n);
            return n;
        } else {
            return rand(m);
        }
    }

    public static void main(String[] args) {
        int m = 4;
        NewClass ne = new NewClass();
        for (int i = 0; i < 4; i++) {
            System.out.println(ne.rand(m));
        }
        System.out.println("list: " + ne.keys);
    }
}

0

有卡片批处理算法:创建有序的数字数组(“卡片批处理”),并在每次迭代中从其随机位置选择一个数字(当然,从“卡片批处理”中删除选定的数字)。


0

是快速创建随机数组的有效解决方案。随机化之后,您只需选择数组的n第-个元素e,然后递增n并返回即可e。该解决方案具有用于获得随机数的O(1)和用于初始化的O(n),但是如果n足够大,那么就需要进行大量折衷。


0

有一个比Collections.shuffle更为有效且麻烦的整数解决方案。

问题与仅从集合中未挑选的项目中连续挑选项目并在其他地方按顺序设置它们相同。这就像随机发牌或从帽子或垃圾箱中抽出中奖彩票一样。

该算法可用于加载任何数组并在加载结束时获得随机顺序。它还可用于添加到List集合(或任何其他索引集合)中,并在添加结束时在集合中获得随机序列。

可以使用创建一次的单个数组或就位的数字排序集合(例如List)来完成。对于数组,初始数组大小必须为包含所有预期值的确切大小。如果您不知道事先可能会出现多少个值,也可以使用大小不变的数字排序集合(例如ArrayList或List)也可以。它将普遍适用于最大为2,000,000,000以上的Integer.MAX_VALUE的任何大小的数组。列表对象将具有相同的索引限制。在获得该大小的阵列之前,计算机可能会耗尽内存。在加载数组之后,加载类型为对象类型的数组并将其转换为某些集合可能会更有效。如果目标集合未进行数字索引,则尤其如此。

完全按照书面说明,此算法将创建一个非常均匀的分布,其中没有重复项。非常重要的一个方面是,必须有可能将下一个项目插入到当前大小+ 1为止。因此,对于第二个项目,可以将其存储在位置0或位置1中对于第20个项目,可以将其存储在0到19之间的任何位置。将第一个项目保留在位置0中,就像将其放置在其他任何位置一样。下一个新项目尽可能地走到任何地方,包括下一个新位置。

序列的随机性将与随机数生成器的随机性一样随机。

该算法还可用于将引用类型加载到数组中的随机位置。由于这适用于数组,因此也可以适用于集合。这意味着您不必创建集合然后进行洗牌或以插入对象的任何顺序对其进行排序。集合只需要能够在集合中的任何位置插入或附加项目。

// RandomSequence.java
import java.util.Random;
public class RandomSequence {

    public static void main(String[] args) {
        // create an array of the size and type for which
        // you want a random sequence
        int[] randomSequence = new int[20];
        Random randomNumbers = new Random();

        for (int i = 0; i < randomSequence.length; i++ ) {
            if (i == 0) { // seed first entry in array with item 0
                randomSequence[i] = 0; 
            } else { // for all other items...
                // choose a random pointer to the segment of the
                // array already containing items
                int pointer = randomNumbers.nextInt(i + 1);
                randomSequence[i] = randomSequence[pointer]; 
                randomSequence[pointer] = i;
                // note that if pointer & i are equal
                // the new value will just go into location i and possibly stay there
                // this is VERY IMPORTANT to ensure the sequence is really random
                // and not biased
            } // end if...else
        } // end for
        for (int number: randomSequence) {
                System.out.printf("%2d ", number);
        } // end for
    } // end main
} // end class RandomSequence

0

确实,这完全取决于您需要随机生成什么,但这是我的看法。

首先,创建一个用于生成随机数的独立方法。确保允许限制。

public static int newRandom(int limit){
    return generatedRandom.nextInt(limit);  }

接下来,您将要创建一个比较值的非常简单的决策结构。这可以通过以下两种方法之一来完成。如果您要验证的数字数量非常有限,则简单的IF语句就足够了:

public static int testDuplicates(int int1, int int2, int int3, int int4, int int5){
    boolean loopFlag = true;
    while(loopFlag == true){
        if(int1 == int2 || int1 == int3 || int1 == int4 || int1 == int5 || int1 == 0){
            int1 = newRandom(75);
            loopFlag = true;    }
        else{
            loopFlag = false;   }}
    return int1;    }

上面将int1到int2到int5进行了比较,并确保随机数中没有零。

有了这两种方法,我们可以执行以下操作:

    num1 = newRandom(limit1);
    num2 = newRandom(limit1);
    num3 = newRandom(limit1);
    num4 = newRandom(limit1);
    num5 = newRandom(limit1);

其次是:

        num1 = testDuplicates(num1, num2, num3, num4, num5);
        num2 = testDuplicates(num2, num1, num3, num4, num5);
        num3 = testDuplicates(num3, num1, num2, num4, num5);
        num4 = testDuplicates(num4, num1, num2, num3, num5);
        num5 = testDuplicates(num5, num1, num2, num3, num5);

如果要验证的列表较长,则更复杂的方法将在代码清晰和处理资源方面产生更好的结果。

希望这可以帮助。这个站点对我有很大帮助,我觉得至少也有TRY的帮助。



0

最简单的方法是使用nano DateTime作为长格式。System.nanoTime();

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.