我想随机遍历一个范围。每个值只会被访问一次,所有值最终都会被访问。例如:
class Array
def shuffle
ret = dup
j = length
i = 0
while j > 1
r = i + rand(j)
ret[i], ret[r] = ret[r], ret[i]
i += 1
j -= 1
end
ret
end
end
(0..9).to_a.shuffle.each{|x| f(x)}
f(x)
对每个值进行操作的函数在哪里。Fisher-Yates shuffle用于有效地提供随机排序。
我的问题是shuffle
需要对数组进行操作,这并不酷,因为我正在处理天文数字。Ruby 会很快消耗大量 RAM 来尝试创建一个巨大的数组。想象一下(0..9)
用(0..99**99)
. 这也是以下代码不起作用的原因:
tried = {} # store previous attempts
bigint = 99**99
bigint.times {
x = rand(bigint)
redo if tried[x]
tried[x] = true
f(x) # some function
}
tried
这段代码非常幼稚,并且随着获得更多条目而迅速耗尽内存。
什么样的算法可以完成我想做的事情?
[Edit1]:我为什么要这样做?我试图用尽哈希算法的搜索空间来寻找 N 长度的输入字符串以寻找部分冲突。我生成的每个数字都相当于一个唯一的输入字符串、熵等等。基本上,我正在使用自定义字母“计数” 。
[Edit2]:这意味着f(x)
在上面的示例中是一种生成散列并将其与部分冲突的常量目标散列进行比较的方法。我不需要存储x
调用后的值,f(x)
因此内存应该随着时间的推移保持不变。
[Edit3/4/5/6]:进一步澄清/修复。
[解决方案]:以下代码基于@bta 的解决方案。为简洁起见,next_prime
未显示。它产生可接受的随机性,并且每个数字只访问一次。有关更多详细信息,请参阅实际帖子。
N = size_of_range
Q = ( 2 * N / (1 + Math.sqrt(5)) ).to_i.next_prime
START = rand(N)
x = START
nil until f( x = (x + Q) % N ) == START # assuming f(x) returns x