算法在[0,8000]范围内生成1000个不同的整数?

时间:2010-04-04 21:53:55

标签: algorithm random permutation

  

可能重复:
  How do you efficiently generate a list of K non-repeating integers between 0 and an upper bound N

有哪些替代方法可以生成[0,8000]范围内的1000个不同的随机整数,而不是以下方法:

  1. 天真的方法:生成一个数字并检查它是否已经在数组中。为O(n ^ 2)
  2. 线性shuffle:生成序列0到8000,shuffle,取第1000个.O(n)

5 个答案:

答案 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)

没有排序的排序列表,O(n)

如果你想整数排序,我在another question得到了很多帮助的答案。您可以使用指数变量来执行此操作,从而避免任何排序。结果是O(n):

Alok's answerDan 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]