从集合中选择 N 个随机数
Posted
技术标签:
【中文标题】从集合中选择 N 个随机数【英文标题】:Choosing N random numbers from a set 【发布时间】:2010-10-04 20:40:56 【问题描述】:我有一个排序集(准确地说是std::set),其中包含具有指定权重的元素。我想从这个集合中随机选择 N 个元素,而权重较高的元素应该有更大的概率被选中。任何元素都可以被多次选择。
我想尽可能高效地执行此操作 - 我想避免对集合进行任何复制(它可能会变得非常大)并在可能的情况下在 O(N) 时间运行。我正在使用 C++,并希望坚持仅使用 STL + Boost 的解决方案。
有人知道 STL/Boost 中是否有执行此任务的函数吗?如果没有,如何实现?
【问题讨论】:
【参考方案1】:您需要计算(并且可能缓存,如果您考虑性能)您的集合中所有权重的总和。然后,生成 N 个不超过该值的随机数。最后,迭代你的集合,计算到目前为止你遇到的权重的总和。检查所有(剩余的)随机数。如果数字介于总和的前一个值和下一个值之间,请插入集合中的值并删除您的随机数。当您的随机数列表为空或您已到达集合的末尾时停止。
【讨论】:
谢谢,这在我的情况下似乎表现不错并且看起来不错。 为了获得最佳性能,请考虑将随机值放在有序集合中,并对其进行一次迭代,而不是对源集的每个值进行迭代。您不必从随机集合中删除值,只需增加迭代器即可。【参考方案2】:我不知道任何图书馆,但听起来你有一个加权轮盘赌。这是一些伪代码的参考,尽管上下文与遗传算法有关:http://www.cse.unr.edu/~banerjee/selection.htm
至于“尽可能高效”,这将取决于数据的某些特征。在加权轮盘的应用中,在搜索索引时可以考虑使用二分搜索。但是,轮盘赌的每个插槽的可能性并非均等,因此按权重顺序检查它们可能是有意义的。
【讨论】:
【参考方案3】:很大程度上取决于您愿意花费多少额外存储空间来加快选择速度。
如果您不愿意使用任何额外的存储空间,@Alex Emelianov 的回答几乎就是我想要发布的内容。如果您愿意使用一些额外的存储空间(并且可能使用与 std::set
不同的数据结构),您可以创建一棵树(如集合使用),但在树的每个节点上,您还可以存储(加权)数字该节点左侧的项目。这将使您能够以对数(而不是线性)复杂性将生成的数字映射到正确的关联值。
【讨论】:
尽管您的算法可能更快,但我还是使用了 Alex 的答案,因为它似乎不是性能瓶颈,而且更容易实现:) 感谢您的回答。以上是关于从集合中选择 N 个随机数的主要内容,如果未能解决你的问题,请参考以下文章