【问题标题】:Choose m elements randomly from a vector containing n elements从包含 n 个元素的向量中随机选择 m 个元素
【发布时间】:2012-03-09 20:19:12
【问题描述】:

我有一个包含n 元素的向量。我需要从向量中随机选择 m 元素的一个子集而不重复。这样做最有效的方法是什么?我需要在我的代码中执行数千次。

我想到的解决方案是使用rand()0n 之间生成一个随机数k。然后选择向量中的kth 元素并将其插入std::set。继续这样做直到集合的大小等于m。我现在确信该集合包含从 n 元素集合中随机选择的 m 唯一元素。

其他可能的解决方案是什么?

谢谢。

【问题讨论】:

  • 在向量上执行std::random_shuffle() 并从中拉出第一个m 元素,也许?
  • @jrok:虽然很简单,但当mn 小很多时效率非常低。
  • @MooingDuck 但事实上std::random_shuffle() 只是一个完整的排列,它也使用了Fisher-Yates shuffle。请参阅 cppreference 中的 first version of possible implementation。对于那些想了解接受的答案以及std::random_shuffle() 的人来说,值得一读。
  • @Rick:当然,这是相同的算法,但不是在m 元素之后停止,而是处理整个数据集,这非常浪费时间。这是std::sortstd::partial_sort 之间的区别。

标签: c++ random vector


【解决方案1】:

你想要一个Fisher-Yates shuffle(M 次迭代后停止):

template<class BidiIter >
BidiIter random_unique(BidiIter begin, BidiIter end, size_t num_random) {
    size_t left = std::distance(begin, end);
    while (num_random--) {
        BidiIter r = begin;
        std::advance(r, rand()%left);
        std::swap(*begin, *r);
        ++begin;
        --left;
    }
    return begin;
}

http://ideone.com/3A3cv 上的演示。这比std::random_shuffle 快得多,当您只需要几个随机数时,即使N==M 也应该是差不多的速度。

【讨论】:

  • @Burr 谢谢!我的向量中有一百万个元素,我需要从中随机选择 100 个元素。这正是我想要的。
  • Ya.. 这是std::random_shuffle.. 的X 选择后停止 版本。我很好奇为什么STL 没有重载这个版本。谢谢顺便说一句:D.
【解决方案2】:

您可以这样做的一种方法是创建向量的所有索引的列表,将它们打乱,然后将第一个 n 作为所选对象的索引:

struct rangegenerator {
    rangegenerator(int init) : start(init) { }

    int operator()() {
        return start++;
    }

    int start;
};

vector<T> numbers; // this is filled somewhere else

vector<int> indices(numbers.size());

generate(begin(indices), end(indices), rangegenerator(0));

random_shuffle(begin(indices), end(indices));

// then take the first n elements of indices and use them as indices into numbers

【讨论】:

  • m 远小于n 时,这是非常低效的。对所有m(其中m 小于n)提出比这更快的答案并不难
  • @Seth:必须同意 Moo。这可能是完成给定任务的最糟糕的方法之一 - 不知道为什么 OP 将其标记为答案。正确答案显然是伯尔的答案。
  • @JaredKrumsie OP 要求“其他可能的解决方案”,而我写的绝对是一个可能的解决方案。答案不正确的唯一方法是它根本不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-21
  • 1970-01-01
  • 2016-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多