算法库
算法库提供大量用途的函数(例如查找、排序、计数、操作),它们在元素范围上操作。注意范围定义为 [first, last)
,其中 last
指代要查询或修改的最后元素的后一个元素。
从一个序列中随机选择 n 个元素
std::sample
template< class PopulationIterator, class SampleIterator, class Distance, class URBG > | (C++17 起) |
从序列 [first; last) 选择 n
个元素,使得每个样本拥有相等的出现概率,并写入这些被选择元素到输出迭代器 out
。用随机数生成器 g
生成随机数。
若 n
大于序列中的元素数量,则选择 last-first 个元素。
算法仅若 PopulationIterator
满足遗留向前迭代器 (LegacyForwardIterator) 要求才稳定(保持被选择元素 的顺序)。
参数
first, last | - | 一对组成自其采样的范围(总体)的迭代器 |
out | - | 写入样本的输出迭代器。必须不在 [first;last) 范围 |
n | - | 要抽取的样本数 |
g | - | 用作随机源的随机数生成器 |
- PopulationIterator 必须满足遗留输入迭代器 (LegacyInputIterator) 的要求。 | ||
- SampleIterator 必须满足遗留输出迭代器 (LegacyOutputIterator) 的要求。 | ||
- 若 PopulationIterator 不满足遗留向前迭代器 (LegacyForwardIterator) ,则 SampleIterator 还必须满足遗留随机访问迭代器 (LegacyRandomAccessIterator) 的要求 | ||
- PopulationIterator 的 value_type 必须可写入到 out | ||
- Distance 必须是整数类型 | ||
- std::remove_reference_t<URBG> 必须满足均匀随机位生成器 (UniformRandomBitGenerator) ,且其返回类型必须可转换为 Distance |
返回值
在输出最后样本后返回 out
的副本,即采样范围的结尾。
复杂度
与 std::distance(first,last) 成线性
注意
此函数可以实现选择抽样或蓄水池抽样。
调用示例
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
#include <functional>
#include <time.h>
#include <random>
#include <vector>
struct Cell
{
int x;
int y;
Cell() = default;
Cell(int a, int b): x(a), y(b) {}
Cell &operator +=(const Cell &cell)
{
x += cell.x;
y += cell.y;
return *this;
}
Cell &operator +(const Cell &cell)
{
x += cell.x;
y += cell.y;
return *this;
}
Cell &operator *(const Cell &cell)
{
x *= cell.x;
y *= cell.y;
return *this;
}
Cell &operator ++()
{
x += 1;
y += 1;
return *this;
}
bool operator <(const Cell &cell) const
{
if (x == cell.x)
{
return y < cell.y;
}
else
{
return x < cell.x;
}
}
bool operator >(const Cell &cell) const
{
if (x == cell.x)
{
return y > cell.y;
}
else
{
return x > cell.x;
}
}
bool operator ==(const Cell &cell) const
{
return x == cell.x && y == cell.y;
}
};
std::ostream &operator<<(std::ostream &os, const Cell &cell)
{
os << "{" << cell.x << "," << cell.y << "}";
return os;
}
int main()
{
std::cout << std::boolalpha;
std::mt19937 g{std::random_device{}()};
srand((unsigned)time(NULL));
auto generate = []()
{
int n = std::rand() % 10 + 110;
Cell cell{n, n};
return cell;
};
//3) 构造拥有 count 个有值 value 的元素的容器。
std::vector<Cell> vector1(8, generate());
std::generate(vector1.begin(), vector1.end(), generate);
std::cout << "vector1: ";
std::copy(vector1.begin(), vector1.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
std::vector<Cell> vector2(vector1.size(), Cell{0, 0});
std::cout << "vector2: ";
std::copy(vector2.begin(), vector2.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
//first, last - 一对组成自其采样的范围(总体)的迭代器
//out - 写入样本的输出迭代器。必须不在 [first;last) 范围
//n - 要抽取的样本数
//g - 用作随机源的随机数生成器
std::sample(vector1.begin(), vector1.end(), vector2.begin(), vector1.size() / 2, std::mt19937{std::random_device{}()});
std::cout << "vector2: ";
std::copy(vector2.begin(), vector2.end(), std::ostream_iterator<Cell>(std::cout, " "));
std::cout << std::endl;
return 0;
}
输出
vector1: {113,113} {113,113} {111,111} {114,114} {118,118} {110,110} {116,116} {110,110}
vector2: {0,0} {0,0} {0,0} {0,0} {0,0} {0,0} {0,0} {0,0}
vector2: {113,113} {114,114} {118,118} {110,110} {0,0} {0,0} {0,0} {0,0}