有效地挑选一个唯一的号码

Efficiently picking a unique number

假设我有一个可能较大的 32 位数字数组,可能有几百万个条目...有没有一种方法可以有效地选择一些没有出现在大批?天真地,我可以只选择一些适当宽度的随机数,然后检查数组,如果它出现在数组中,返回并选择另一个,但由于数组中元素的数量,可能需要重新扫描数组的成本反复令人担忧。在实践中,我不确定这会有多大问题,因为可能永远不会超过 2000 万个条目,而唯一值的数量是几十亿,所以可能需要重新扫描的总体可能性该数组将很少发生,因此这不是问题。尽管如此,这种算法可能会多次重复重新扫描数组这一事实对我来说很麻烦,如果能找到更好的解决方案,我理想情况下会喜欢。从技术上讲,数字甚至不必是随机的...确定性值是可以接受的,唯一的要求是产生的数字必须是唯一的,并且没有出现在列表中。

所以...是否有一种运行时有效的方法来生成唯一数字,或者我上面描述的随机数方法是唯一可行的方法吗?关于 time/space 权衡,我对速度更感兴趣,因此保证 O(n) 算法是理想的,但我可能不希望任何额外的 space 要求大于大约 O( n log n).

这最终将在 C 中实现,但可以接受任何语言中性术语的算法描述。

扫描大型数组的大部分开销都在内存访问中。您可以通过选择一小组候选随机数来大大降低重新扫描的风险。

在扫描期间,将集合中的每个成员与当前数组元素进行比较。如果匹配则删除集合成员。如果这使得集合变空,则您必须返回并重新开始一个新集合。如果您以非空候选集结束,请选择任何幸存的成员。

一个好的解决方案是按照你说的去做(选择和重新选择碰撞)但将数字保持在散列中-table。

如果您排除的数字数组本身分布良好,您甚至不需要哈希函数。

确保按排序顺序存储碰撞,以减少大约 1/2 的工作量。理想情况下,将桶碰撞放入二叉树中,但排序的链表可能适用于您的数字。

这很好,因为它可以通过调整桶的数量进行调整。

一旦你构建了散列,它就是 O(N)-table。如果您尝试选择 'without replacement' 并在每一步将找到的那个添加到 'exclude' 列表中,则它是渐近平均 O(N^2)。但是,N^2 上的常数在您的规模下可能会很小。

请注意,选择一个随机的 32 位值具有大约 1:2000 个 'hitting' 个 'exclude' 个 2,000,000 个列表。

如果排除列表更密集 (K ~ 2^32-1),您最终会在 (0,2^31-1-K) 范围内确定一个随机数,然后计算到正确的间隙。 但是你的数字肯定通过了任何测试,因为与池大小相比,排除项很小。

如果您不太关心统计准确性,您可以直接跳进去,如果您击中 'exclude',则 +1。

如果您要在某些模拟或密码学应用程序中生成准确的统计数据,请不要选择 +1。如果您是游戏编程或只是在(比如说)自动化测试套件中寻找健康的传播,我希望它没问题。请注意 'clumping' 与 'exclude' 密度成正比。

一个Bloom Filter可以满足您的需要。它可以让您对百万元素数组进行简明总结,并提供快速成员资格测试。它允许误报但不允许误报,这适用于不需要完美随机性的应用程序。

# python-style-psuedo-code

# build concise searchable summary of the known members
members = BloomFilter(data)

# choose 1000 values known not to be in the members
for i in range(1000):
    candidate = random.randrange(2 ** 32)
    while candidate in members:
          candidate = random.randrange(2 ** 32)
    print candidate

此解决方案的插入时间为 O(n),查找唯一编号的时间最多为 O(n),但可能要少得多。

再做一个2n位的结构体,每两位代表列表中是否存在数组元素(element + 1)和(element - 1)

要找到唯一的数字,请遍历位结构,直到遇到设置为零的位。

在数组中插入新数字时,更新相应的位。例如,插入元素 2,数组中代表任何 3 和 1 的位将被更新以显示 3-1(在 3 的情况下)和 1+1(在 1 的情况下)现在存在于数组。

Insertion/deletion 可以通过添加从每个元素到具有相同整数的下一个元素的指针来减少时间。

(改编自我在这里的回答Efficiently choose an integer distinct from all elements of a list