【发布时间】:2010-09-13 06:47:05
【问题描述】:
我在 Vector 中有一组对象,我想从中选择一个随机子集(例如,返回 100 个项目;随机选择 5 个)。在我的第一次(非常仓促的)传球中,我做了一个非常简单但可能过于聪明的解决方案:
Vector itemsVector = getItems();
Collections.shuffle(itemsVector);
itemsVector.setSize(5);
虽然这具有美观和简单的优点,但我怀疑它不会很好地扩展,即 Collections.shuffle() 必须至少为 O(n)。我不太聪明的选择是
Vector itemsVector = getItems();
Random rand = new Random(System.currentTimeMillis()); // would make this static to the class
List subsetList = new ArrayList(5);
for (int i = 0; i < 5; i++) {
// be sure to use Vector.remove() or you may get the same item twice
subsetList.add(itemsVector.remove(rand.nextInt(itemsVector.size())));
}
关于从集合中抽取随机子集的更好方法有什么建议吗?
【问题讨论】:
-
严格来说,您的代码假定您正在处理一个列表/向量。如果您处理任意集合,您首先必须将其所有项目提取到一个列表/向量/数组中,这可能非常昂贵。这是因为通常的洗牌算法只适用于列表/数组。
-
我发现弗洛伊德的算法可以在所有子集上提供可证明的均匀分布,所以我强烈推荐 Eyal Schneider's answer,它链接到详细介绍它的帖子,包括。证明和实施。
-
itemsVector.remove 是 O(n) docs.oracle.com/javase/7/docs/api/java/util/…。我认为 O(k) 的运行时间是可能的。
标签: java algorithm collections random subset