简体   繁体   English

在 C++ 中采样 3 个没有替换的整数

[英]Sample 3 integers without replacement in C++

I want to sample three integers among {0, 1, ..., n-1} without replacement.我想在不替换的情况下对{0, 1, ..., n-1}三个整数进行采样。

Here is how I proceed so far:到目前为止,我是这样进行的:

#include <random>

/* constructs vector {0, 1, ..., n-1} --------------------------------------- */
template <class T>
std::vector<T> integers_n(T n) {
  std::vector<T> out(n);
  for(T i = 0; i < n; i++) {
    out[i] = i;
  }
  return out;
}

/* samples three integers among {0, 1, ..., n-1} ---------------------------- */
const std::vector<int> choose3(const int n,
                               std::default_random_engine& generator) {
  std::uniform_int_distribution<int> sampler1(0, n - 1);
  std::uniform_int_distribution<int> sampler2(0, n - 2);
  std::uniform_int_distribution<int> sampler3(0, n - 3);
  const int i1 = sampler1(generator);
  const int i2 = sampler2(generator);
  const int i3 = sampler3(generator);
  std::vector<int> elems = integers_n(n);
  elems.erase(elems.begin() + i1);
  const int j2 = elems[i2];
  elems.erase(elems.begin() + i2);
  const int j3 = elems[i3];
  return {i1, j2, j3};
}

This works but is there a better way?这有效,但有更好的方法吗?

I want to perform this sampling multiple times, in a loop.我想在循环中多次执行此采样。 Is it time-consuming to redefine the samplers for each iteration?为每次迭代重新定义采样器是否耗时?

For technical reasons, I am restricted to C++ 11.由于技术原因,我只能使用 C++ 11。

You can sample without replacement from 0, ..., n - 1 without allocating any additional memory;您可以在不分配任何额外内存的情况下从0, ..., n - 1进行无替换采样; elem is unneeded. elem是不需要的。 The key is to simulate a few steps of the Fisher-Yates Shuffle , as seen in David Eisenstat's answer to my related question .关键是模拟Fisher-Yates Shuffle的几个步骤,如David Eisenstat 对我的相关问题的回答所示

// std::array<int, 3> requires no heap allocation, so is a better choice.
std::array<int, 3> choose3(const int n,
                           std::default_random_engine& generator) {
    std::uniform_int_distribution<int> sampler1(0, n - 1);
    std::uniform_int_distribution<int> sampler2(0, n - 2);
    std::uniform_int_distribution<int> sampler3(0, n - 3);
    // Algorithm translated from https://stackoverflow.com/a/64359519/1896169
    int i1 = sampler1(generator);
    int i2 = sampler2(generator);
    int i3 = sampler3(generator);

    if (i3 == i2) i3 = n - 2;
    if (i3 == i1) i3 = n - 1;
    if (i2 == i1) i2 = n - 1;
    return {i1, i2, i3};
}

Rather than using erase , you can replace the element chosen from the vector by the last element.您可以用最后一个元素替换从向量中选择的元素,而不是使用erase

elems[i1] = elems[n - 1];

Then do the same for the second:然后对第二个做同样的事情:

elems[i2] = elems[n - 2];

The time to construct the three uniform_int_distribution is minimal.构建三个uniform_int_distribution的时间是最少的。 Constructing elems will consume more time.构建elems会消耗更多时间。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM