如何生成随机整数但确保它们不会重复?
现在我用:
Random randomGenerator = new Random();
randomGenerator.nextInt(100);
EDIT I
我正在寻找最有效的方式,或者最不好的方式
EDIT II
范围并不重要
答案 0 :(得分:15)
ArrayList<Integer> list = new ArrayList<Integer>(100);
for(int i = 0; i < 100; i++)
{
list.add(i);
}
Collections.shuffle(list);
现在,list
包含数字0到99,但是是随机顺序。
答案 1 :(得分:6)
如果您想要的是伪随机非重复数字序列,那么您应该查看linear feedback shift register。它将产生介于0和给定功率2之间的所有数字,而不会重复。您可以通过选择最接近的2的较大幂并将所有结果丢弃到N来轻松地将其限制为N.它没有其他基于集合的解决方案所具有的内存限制。
您可以找到java实现here
答案 2 :(得分:4)
如何生成随机整数但确保它们不会重复?
首先,我想指出数字不重复的约束使它们按照定义非随机。
我认为您真正需要的是在某个范围内随机生成的排列数字;例如0
到99
。即使这样,一旦你使用了范围内的所有数字,重复是不可避免的。
显然,您可以增加范围的大小,这样您就可以获得更大的数字,而无需重复。但是当你这样做时,你会遇到生成器需要记住以前生成的所有数字的问题。对于占用大量内存的大N
。
记住大量数字的替代方法是使用具有长周期长度的伪随机数生成器,并将生成器的整个状态作为“随机”数返回。这保证不会重复数字...直到发电机循环。
(这个答案可能超出OP感兴趣的范围......但是有人可能觉得它很有用。)
答案 3 :(得分:2)
如果你有一个非常大的整数范围(&gt;&gt; 100),那么你可以将生成的整数放入哈希表中。生成新的随机数时,继续生成,直到得到一个不在哈希表中的数字。
答案 4 :(得分:1)
Matthew Flaschen的解决方案适用于小数字。如果您的范围非常大,那么使用某种Set
来跟踪使用的数字可能会更好:
Set usedNumbers = new HashSet();
Random randomGenerator = new Random();
int currentNumber;
while(IStillWantMoreNumbers) {
do {
currentNumber = randomGenerator.nextInt(100000);
} while (usedNumbers.contains(currentNumber));
}
你必须要小心这一点,因为随着“使用”数字的比例增加,这个函数所花费的时间将呈指数增长。如果您的范围远大于您需要生成的数字量,那真的是个好主意。
答案 5 :(得分:1)
根据应用程序的不同,您还可以生成严格增加的序列,即从种子开始并在一个范围内添加一个随机数,然后将该结果重新用作下一个数字的种子。您可以通过调整范围来设置可猜测的范围,将其与您需要的数量进行平衡(如果您进行的增量步长达到1,000,则不会非常快地耗尽64位无符号整数,例如)。
当然,如果你试图在加密意义上创建某种不可篡改的数字,这是非常糟糕的,但是具有非重复序列可能会对基于它的任何密码提供合理有效的攻击,所以我我希望你不要在任何安全环境中使用它。
也就是说,这种解决方案不容易发生计时攻击,其他一些建议也是如此。
答案 6 :(得分:1)
由于我没有足够的声誉(这似乎是倒退的......)我不能评论上面的早期答案,我不应该评论别人的答案,但不能提供我自己的答案吗?...无论如何......),我想提一下依赖于Collections.shuffle()的一个主要缺陷,它与你的集合的内存限制没什么关系:
Collections.shuffle()使用Random对象,它在Java中使用48位种子。这意味着有281,474,976,710,656种可能的种子值。这似乎很多。但是考虑一下你是否想用这种方法来洗牌52张牌。一张52张牌有52张牌! (超过8 * 10 ^ 67种可能的配置)。如果您使用相同的种子,您将始终获得相同的混洗结果,您可以看到Collections.shuffle()可以生成的52卡牌组的可能配置只是所有可能配置的一小部分。 / p>
事实上,Collections.shuffle()不是一个很好的解决方案,可以对16个元素的任何集合进行混洗。一个17元素的集合有17个!或355,687,428,096,000个配置,这意味着74,212,451,385,344配置将永远不会成为Collections.shuffle()的17个元素列表的结果。
根据您的需要,这可能非常重要。糟糕/随机化技术的选择不当会使您的软件容易受到攻击。例如,如果您使用Collections.shuffle()或类似的算法来实现商业扑克服务器,您的改组将会有偏见,精明的计算机辅助玩家可以利用这些知识为他们带来好处,因为它会扭曲赔率。
答案 7 :(得分:1)
如果你想要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的力量。
答案 8 :(得分:0)
如果值范围不是有限的,则可以创建一个使用List的对象来跟踪已使用整数的范围。每次需要一个新的随机整数时,都会生成一个并根据使用的范围进行检查。如果整数未使用,则将该整数添加为新使用的Range,将其添加到现有的使用范围,或者根据需要合并两个范围。
但你可能真的想要Matthew Flaschen的解决方案。
答案 9 :(得分:0)
Linear Congruential Generator可用于生成具有不同随机数的循环(完整循环)。