我想生成一个介于0到1000之间的永不重复的唯一随机数(即6不会出现两次),但是这并不能像对先前值进行O(N)搜索那样进行。这可能吗?
使用0-1000值初始化一个1001个整数的数组,并将变量max设置为数组的当前max索引(从1000开始)。选择一个介于0和max之间的随机数r,将位置r处的数字与位置max处的数字交换,然后立即将位置max处的数字返回。最大减1,然后继续。当max为0时,将max设置回数组的大小-1,然后重新启动,而无需重新初始化数组。
更新: 尽管我回答问题时是自己提出了这种方法,但是经过一些研究后,我意识到这是费舍尔·耶茨的改良版,称为Durstenfeld- Fisher-Yates或Knuth-Fisher-Yates。由于描述可能会有些困难,因此我在下面提供了一个示例(使用11个元素而不是1001):
数组以初始化为array [n] = n的11个元素开始,最大值从10开始:
+--+--+--+--+--+--+--+--+--+--+--+ | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10| +--+--+--+--+--+--+--+--+--+--+--+ ^ max
每次迭代时,都会在0到max之间选择一个随机数r,将array [r]和array [max]交换,返回新的array [max],并将max减1:
max = 10, r = 3 +--------------------+ v v +--+--+--+--+--+--+--+--+--+--+--+ | 0| 1| 2|10| 4| 5| 6| 7| 8| 9| 3| +--+--+--+--+--+--+--+--+--+--+--+ max = 9, r = 7 +-----+ v v +--+--+--+--+--+--+--+--+--+--+--+ | 0| 1| 2|10| 4| 5| 6| 9| 8| 7: 3| +--+--+--+--+--+--+--+--+--+--+--+ max = 8, r = 1 +--------------------+ v v +--+--+--+--+--+--+--+--+--+--+--+ | 0| 8| 2|10| 4| 5| 6| 9| 1: 7| 3| +--+--+--+--+--+--+--+--+--+--+--+ max = 7, r = 5 +-----+ v v +--+--+--+--+--+--+--+--+--+--+--+ | 0| 8| 2|10| 4| 9| 6| 5: 1| 7| 3| +--+--+--+--+--+--+--+--+--+--+--+ ...
经过11次迭代后,已选择数组中的所有数字,max == 0,并且对数组元素进行了混洗:
+--+--+--+--+--+--+--+--+--+--+--+ | 4|10| 8| 6| 2| 0| 9| 5| 1| 7| 3| +--+--+--+--+--+--+--+--+--+--+--+
此时,最大可以重置为10,并且该过程可以继续。