假设我想以随机顺序生成1-1000的所有整数。但...
我认为这应该是不可能的,但也许我只是没有考虑正确的解决方案。
我想在C#中使用它,但我对approche然后实际的实现更感兴趣。
答案 0 :(得分:3)
加密。加密是两组之间的一对一映射。如果两个集合相同,则它是由加密密钥指定的排列。写/找到将{0,1000}映射到自身的加密。阅读Format Preserving Encryption(FPE)以帮助您。
要生成随机顺序,只需按顺序加密数字0,1,2 .......您不需要存储它们,只需跟踪您在列表中的位置。
从实际的角度来看,{0,1023}中的数字会更容易处理,因为它是一个块大小为10位的块密码,你可以编写一个简单的Feistel cipher来生成你的号码。你可能想要这样做,只需重新加密1000以上的数字 - FPE的循环步行方法。
答案 1 :(得分:2)
如果随机性不是主要问题,您可以使用linear congruential generator。由于当模数为素数时,LCG不会产生最大长度序列,因此您需要选择较大的模数(2的最大幂次是明显的选择)并跳过所需范围之外的任何值。 / p>
我担心C#不是我的事,但希望以下Python不言自明。如果要在非常小的范围内生成序列,则需要进行一些调整:
# randint(a, b) returns a random integer in the range (a..b) (inclusive)
from random import randint
def lcg_params(u, v):
# Generate parameters for an LCG that produces a maximal length sequence
# of numbers in the range (u..v)
diff = v - u
if diff < 4:
raise ValueError("Sorry, range must be at least 4.")
m = 2 ** diff.bit_length() # Modulus
a = (randint(1, (m >> 2) - 1) * 4) + 1 # Random odd integer, (a-1) divisible by 4
c = randint(3, m) | 1 # Any odd integer will do
return (m, a, c, u, diff + 1)
def generate_pseudorandom_sequence(rmin, rmax):
(m, a, c, offset, seqlength) = lcg_params(rmin, rmax)
x = 1 # Start with a seed value of 1
result = [] # Create empty list for output values
for i in range(seqlength):
# To generate numbers on the fly without storing them in an array,
# just run the following while loop to fetch a new number
while True:
x = (x * a + c) % m # Iterate LCG until we get a value in the
if x < seqlength: break # required range
result.append(x + offset) # Add this value to the list
return result
>>> generate_pseudorandom_sequence(1, 20)
[4, 6, 8, 1, 10, 3, 12, 5, 14, 7, 16, 9, 18, 11, 20, 13, 15, 17, 19, 2]