假设我想以随机顺序生成1-1000之间的所有整数,但是...
我想在C#中使用它,但我更感兴趣的是方法而不是实际实现。
- 不能重复生成数字
- 没有存储所有可能数字的数组、列表...
- 没有存储已生成的数字。
- 最终不能缺少任何数字。
我想在C#中使用它,但我更感兴趣的是方法而不是实际实现。
加密。加密是两个集合之间的一对一映射。如果这两个集合相同,则它是由加密密钥指定的置换。编写/查找一种将{0, 1000}映射到自身的加密方式。在此处阅读Format Preserving Encryption (FPE)。
为了生成随机顺序,只需按顺序加密数字0、1、2等。您不需要存储它们,只需跟踪您已经通过列表走了多远。
从实用角度来看,使用{0, 1023}中的数字会更容易处理,因为这将是一个块密码,块大小为10位,您可以编写一个简单的Feistel cipher来生成您的数字。您可能仍然想这样做,并重新加密超过1000的数字--即FPE的周期行走方法。
# 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]