可能重复:
How do you efficiently generate a list of K non-repeating integers between 0 and an upper bound N
有哪些替代方法可以生成[0,8000]范围内的1000个不同的随机整数,而不是以下方法:
答案 0 :(得分:12)
您可以使用使用互换实施的部分Fisher-Yates shuffle。此算法的一个不错的功能是,如果您在k
互换后停止,则第一个k
数字是整个集合中k
的随机样本。
答案 1 :(得分:2)
您可以创建一个包含数字0到8000的列表。
然后循环1000次会生成0到列表长度之间的随机数。
从列表中删除该元素并将其添加到输出列表中。
删除元素后,请确保您的选择是唯一的。
while (outputList.Count < 1000)
{
index = random.Next(0, inputList.Count);
outputList.Add(inputList[index]);
inputList.RemoveAt(index);
}
答案 2 :(得分:1)
这是来自Knuth的编程艺术(通过Jon Bentley的编程珍珠),用Python实现:
import random
# randomly select m numbers from n candidates
def random_select(m, n):
select = m
result = []
for i in xrange(n):
if random.randint(0, n-i) < select:
result.append(i)
select -= 1
return result
random_select(1000, 8000)
这将按数字顺序生成随机数列表。它的工作原理是迭代0-n(即0-8000)的所有整数,并以(左数选择数/剩余候选数)的概率随机选择它们。它在O(n)中运行,所以如果n与m相比非常大,请不要尝试 - 例如从十亿中选出10个数字。它不使用除结果列表(m)和一些局部变量之外的其他内存,这与依赖于混洗长度为n的列表的解决方案不同。
如果您希望以随机顺序显示结果,则随后将列表随机播放。
答案 3 :(得分:1)
部分Fisher-Yates,正如@Mark建议的那样,稍微扭曲一下,存储掉路.21
这样,最多消耗的内存与结果列表O(m)一样多
它也将以O(m) - 而不是O(n)运行,作为列举整个范围的其他解决方案 - 因此它不应该在较大范围内出现问题。
通过这种方式,您可以充分利用这两个方面。
/// <summary>
/// Generates unique random numbers
/// <remarks>
/// Worst case memory usage is O(min((emax-imin)/2, num))
/// </remarks>
/// </summary>
/// <param name="random">Random source</param>
/// <param name="imin">Inclusive lower bound</param>
/// <param name="emax">Exclusive upper bound</param>
/// <param name="num">Number of integers to generate</param>
/// <returns>Sequence of unique random numbers</returns>
public static IEnumerable<int> UniqueRandoms(
Random random, int imin, int emax, int num)
{
int dictsize = num;
long half = (emax - (long)imin + 1) / 2;
if (half < dictsize)
dictsize = (int)half;
Dictionary<int, int> trans = new Dictionary<int, int>(dictsize);
for (int i = 0; i < num; i++)
{
int current = imin + i;
int r = random.Next(current, emax);
int right;
if (!trans.TryGetValue(r, out right))
{
right = r;
}
int left;
if (trans.TryGetValue(current, out left))
{
trans.Remove(current);
}
else
{
left = current;
}
if (r > current)
{
trans[r] = left;
}
yield return right;
}
}
答案 4 :(得分:0)
如果你想整数排序,我在another question得到了很多帮助的答案。您可以使用指数变量来执行此操作,从而避免任何排序。结果是O(n):
从Alok's answer和Dan Dyer's comment可以看出,对一组增量使用exponential distribution可以按顺序给出整数的均匀分布。
因此,您只需开始生成数字,然后在结尾处进行缩放。在delta中添加1可确保您永远不会重复值。
import random,sys,math
def genSortedInts(mini,maxi,vals):
running = 0
deltas = [random.expovariate(1.0) for i in range(0,vals+1)]
floats = []
for d in deltas:
running += d
floats.append(running)
upper = floats.pop()
valRange = maxi-mini-(vals-1)
ints = [mini+int(f/upper*valRange)+id for id,f in enumerate(floats)]
return ints
if __name__ == "__main__":
vals = 10
maxi = 80
mini = 0
print(genSortedInts(mini,maxi,vals))
请注意使用random.expovariate(1.0)
,Python exponential distribution random number generator(非常有用!)。在这里,它的平均值为1.0(arg为1 / mean),但由于脚本与序列中的最后一个数相对,因此平均值本身并不重要。
输出(公平骰子滚动)10个值,最高为80:
[3, 5, 10, 16, 25, 37, 41, 45, 57, 70]