簡體   English   中英

在Java中生成隨機整數

[英]Generate random integers in java

如何生成隨機整數,但要確保它們不會重復?

現在我使用:

Random randomGenerator = new Random();
randomGenerator.nextInt(100);

EDIT I

我正在尋找最有效的方法,或者最糟糕的方法

EDIT II

范圍不重要

ArrayList<Integer> list = new ArrayList<Integer>(100);
for(int i = 0; i < 100; i++)
{
  list.add(i);
}
Collections.shuffle(list);

現在, list包含數字0到99,但順序隨機。

如果您想要的是偽隨機非重復數字序列,則應查看線性反饋移位寄存器 它將產生0到給定2的冪之間的所有數字,而無需重復。 您可以通過選擇最接近的2的大方冪並舍棄N上的所有結果,輕松地將其限制為N。它不具有此處基於其他大學模式的解決方案所具有的內存限制。

您可以在這里找到Java實現

如何生成隨機整數,但要確保它們不會重復?

首先,我只是想指出,這些數字不重復的約束使得他們的非隨機的定義

我認為您真正需要的是在一定范圍內隨機生成的數字排列 例如099 即使這樣,一旦使用了該范圍內的所有數字,就不可避免地需要重復。

顯然,您可以增加范圍的大小,以便獲得更大的數字而無需重復。 但是,當您執行此操作時,就會遇到生成器需要記住所有先前生成的數字的問題。 對於較大的N ,這會占用大量內存。

記住大量數字的另一種方法是使用周期長的偽隨機數生成器,然后將生成器的整個狀態作為“隨機”數返回。 這樣可以保證沒有重復的數字...直到發電機循環。

(此答案可能超出了OP感興趣的范圍,但可能有人覺得有用。)

如果整數范圍很大(>> 100),則可以將生成的整數放入哈希表中。 生成新的隨機數時,請繼續生成,直到獲得哈希表中沒有的數字為止。

由於我沒有足夠的聲譽而無法在上面的早期答案中發表評論(這似乎是倒退的……我不應該評論別人的答案,但不能提供自己的答案嗎? 。),我想指出的是,依賴Collections.shuffle()有一個主要缺陷,它與您的集合的內存限制無關:

Collections.shuffle()使用隨機對象,在Java中使用48位種子。 這意味着可能有281,474,976,710,656個種子值。 好像很多。 但是請考慮是否要使用此方法來洗牌52張牌。 52張牌中有52張! (超過8 * 10 ^ 67種可能的配置)。 由於如果使用相同的種子,將始終獲得相同的混洗結果,因此可以看到Collections.shuffle()可以生成的52張卡片組的可能配置只是所有​​可能配置的一小部分。

實際上,對於將超過16個元素的任何集合進行混洗,Collections.shuffle()並不是一個好的解決方案。 一個17個元素的集合有17個! 或355,687,428,096,000配置,這意味着74,212,451,385,344個配置將永遠不是17個元素列表的Collections.shuffle()的結果。

根據您的需求,這可能非常重要。 隨機/隨機化技術選擇不當會使您的軟件容易受到攻擊。 例如,如果您使用Collections.shuffle()或類似的算法來實現商用撲克服務器,則您的混洗將有偏見,並且精明的計算機輔助玩家可以利用這些知識來受益,因為這會使賠率發生偏差。

如果要在0到255之間使用256個隨機數,請生成一個隨機字節,然后將其與計數器異或。

byte randomSeed = rng.nextInt(255);
for (int i = 0; i < 256; i++) {
    byte randomResult = randomSeed ^ (byte) i;
    << Do something with randomResult >>
}

適用於2的任何冪。

馬修·弗拉申(Matthew Flaschen)的解決方案適用於少數人。 如果您的范圍確實很大,則最好使用某種Set來跟蹤使用的數字:

Set usedNumbers = new HashSet();
Random randomGenerator = new Random();
int currentNumber;
while(IStillWantMoreNumbers) {
    do {
        currentNumber = randomGenerator.nextInt(100000);
    } while (usedNumbers.contains(currentNumber));
}

但是,您必須對此小心,因為隨着“已使用”數字的比例增加,此功能花費的時間將成倍增加。 如果您的范圍比您需要生成的數字量大得多,這實際上只是一個好主意。

根據應用程序的不同,您還可以生成嚴格增加的序列,即從種子開始並向其添加一個范圍內的隨機數,然后將該結果重新用作下一個數字的種子。 您可以通過調整范圍來設置可猜測性,將其與所需的數字進行平衡(如果您遞增的步數最多為1,000,那么您將不會很快用盡64位無符號整數,例如)。

當然,如果您嘗試創建某種意義上的不可猜測的數字,這是非常糟糕的,但是具有非重復序列可能會對基於它的任何密碼提供合理有效的攻擊,所以我希望您不會在任何類型的安全上下文中使用此方法。

就是說,這種解決方案不容易受到定時攻擊的影響,而其他一些建議就是這樣。

如果值的范圍不是有限的,則可以創建一個使用列表的對象,以跟蹤使用的整數的范圍。 每次需要一個新的隨機整數時,都會生成一個整數並對照使用的范圍進行檢查。 如果未使用該整數,則它將將該整數添加為新的使用范圍,將其添加到現有的使用范圍,或適當合並兩個范圍。

但是您可能真的想要Matthew Flaschen的解決方案。

線性同余生成器可用於生成具有不同隨機數的周期(完整周期)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM