Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何从C++;集装箱?_C++_Algorithm_Stl - Fatal编程技术网

C++ 如何从C++;集装箱?

C++ 如何从C++;集装箱?,c++,algorithm,stl,C++,Algorithm,Stl,从STL范围获取[pseudo-]随机元素的好方法是什么 我能想到的最好办法是执行std::random\u shuffle(c.begin(),c.end()),然后从c.begin()中提取我的随机元素 然而,我可能想要一个来自const容器的随机元素,或者我可能不想要一次完全洗牌的代价 有更好的方法吗?获取元素数,c.size(),然后获取介于0和c.size()之间的随机数,并使用: auto it = c.begin(); std::advance(it, random_number)

从STL范围获取[pseudo-]随机元素的好方法是什么

我能想到的最好办法是执行
std::random\u shuffle(c.begin(),c.end())
,然后从
c.begin()
中提取我的随机元素

然而,我可能想要一个来自
const
容器的随机元素,或者我可能不想要一次完全洗牌的代价


有更好的方法吗?

获取元素数,
c.size()
,然后获取介于0和
c.size()
之间的
随机数,并使用:

auto it = c.begin();
std::advance(it, random_number)

查看一下

您可以尝试获取一个介于0和容器元素数之间的随机数。然后可以访问容器的相应元素。例如,您可以执行以下操作:

#include <cstdlib>
#include <ctime>

// ...
std::srand(std::time(0)); // must be called once at the start of the program
int r = std::rand() % c.size() + 1; 
container_type::iterator it = c.begin();
std::advance(it, r);
#包括
#包括
// ...
标准::srand(标准::时间(0));//必须在程序开始时调用一次
int r=std::rand()%c.size()+1;
容器类型::迭代器it=c.begin();
标准:前进(it,r);

只要远大于容器大小,此操作就可以正常工作,否则会出现偏差问题:

vector::迭代器randIt=myvector.begin();
std::advance(randIt,std::rand()%myvector.size());

如果您无法访问尺寸,我想您应该执行以下操作。它将迭代器返回给随机元素

#include <algorithm>
#include <iterator>

template <class InputIterator> InputIterator 
random_n(InputIterator first, InputIterator last) {
   typename std::iterator_traits<InputIterator>::difference_type distance = 
        std::distance(first, last);
   InputIterator result = first;
   if (distance > 1) {
      // Uses std::rand() naively.  Should replace with more uniform solution. 
      std::advance( result, std::rand() % distance );
   }
   return result;
}
// Added in case you want to specify the RNG.  RNG uses same 
// definition as std::random_shuffle
template <class InputIterator, class RandomGenerator> InputIterator 
random_n(InputIterator first, InputIterator last, RandomGenerator& rand) {
   typename std::iterator_traits<InputIterator>::difference_type distance = 
       std::distance(first, last);
   InputIterator result = first;
   if (distance > 1) {
      std::advance( result, rand(distance) );
   }
   return result;
}
#包括
#包括
模板输入计算器
随机(先输入计数器,后输入计数器){
typename std::迭代器特性::差异类型距离=
标准:距离(第一个、最后一个);
输入计算器结果=第一个;
如果(距离>1){
//天真地使用std::rand()。应替换为更统一的解决方案。
std::Advanced(结果,std::rand()%距离);
}
返回结果;
}
//如果要指定RNG,则添加。RNG使用相同的方法
//定义为std::随机洗牌
模板输入计算器
随机(先输入计数器,后输入计数器,随机生成器和随机数){
typename std::迭代器特性::差异类型距离=
标准:距离(第一个、最后一个);
输入计算器结果=第一个;
如果(距离>1){
标准::前进(结果,兰德(距离));
}
返回结果;
}

此处使用
%
的所有答案都是不正确的,因为
rand()%n
将产生有偏差的结果:想象
rand\u MAX==5
,元素数为4。然后你会得到比数字2或3多两倍的数字0和1

正确的方法是:

template <typename I>
I random_element(I begin, I end)
{
    const unsigned long n = std::distance(begin, end);
    const unsigned long divisor = (RAND_MAX + 1) / n;

    unsigned long k;
    do { k = std::rand() / divisor; } while (k >= n);

    std::advance(begin, k);
    return begin;
}
模板
I随机元素(我开始,我结束)
{
const unsigned long n=std::distance(开始、结束);
常量无符号长除数=(RAND_MAX+1)/n;
无符号长k;
do{k=std::rand()/divisior;}而(k>=n);
标准:前进(开始,k);
返回开始;
}

另一个问题是,
std::rand
只假设有15个随机位,但我们在这里忘记了这一点。

我在Google+的一篇文章中发布了这个解决方案,其他人引用了它。在此处发布,因为此版本比其他版本稍好,因为它通过使用std::uniform_int_分布避免了偏差:

#include  <random>
#include  <iterator>

template<typename Iter, typename RandomGenerator>
Iter select_randomly(Iter start, Iter end, RandomGenerator& g) {
    std::uniform_int_distribution<> dis(0, std::distance(start, end) - 1);
    std::advance(start, dis(g));
    return start;
}

template<typename Iter>
Iter select_randomly(Iter start, Iter end) {
    static std::random_device rd;
    static std::mt19937 gen(rd());
    return select_randomly(start, end, gen);
}
#包括
#包括
模板
Iter随机选择(Iter开始、Iter结束、随机发生器和g){
标准:均匀分布(0,标准:距离(起点、终点)-1);
std::前进(开始,dis(g));
返回启动;
}
模板
Iter随机选择(Iter开始、Iter结束){
静态std::随机_设备rd;
静态标准::mt19937 gen(rd());
返回随机选择_(开始、结束、生成);
}
示例用途为:

#include <vector>
using namespace std;

vector<int> foo;
/* .... */
int r = *select_randomly(foo.begin(), foo.end());
#包括
使用名称空间std;
矢量foo;
/* .... */
int r=*随机选择_(foo.begin(),foo.end());

我最终创建了一个。

您可以使用0~1随机函数为容器中的每个元素生成一个浮点数作为其分数。 然后选择得分最高的一个。

C++17

这是一种不重复地获得多个随机元素的方便方法

main.cpp

#include <algorithm>
#include <iostream>
#include <random>
#include <vector>

int main() {
    const std::vector<int> in{1, 2, 3, 5, 7};
    std::vector<int> out;
    size_t nelems = 3;
    std::sample(
        in.begin(),
        in.end(),
        std::back_inserter(out),
        nelems,
        std::mt19937{std::random_device{}()}
    );
    for (auto i : out)
        std::cout << i << std::endl;
}
输出:从
1、2、3、5、7
中选取3个随机数,不重复

为了提高效率,只保证
O(n)
,因为
ForwardIterator
是使用的API,但我认为stdlib实现将在可能的情况下专用于
O(1)
(例如
vector


在GCC 7.2和Ubuntu 17.10中测试

使用std::advance(c.begin(),随机数)
。例如,
std::set
中的迭代器是双向的,而不是随机访问的。@Alexandre:另一方面,OP目前使用的是
random\u shuffle
,这需要随机访问迭代器,所以他似乎对该限制没有意见。@Björn:说得好。不过,使用
std::distance
更为通用(OP想要的是作用于某个范围的东西)。@AlexandreC,不幸的是,所以你需要分别提前和取消引用。我真的不明白你想要什么。你是不是每次都想要一个随机数而不是一个序列?如果是这样,您可以调用sran(time(NULL));然后调用rand();我最喜欢这个解决方案。如果迭代器是随机访问的,则为O(1),但如果需要,它也可用于简单的输入迭代器。如果
RAND_MAX
不能被元素数平均整除,则此方法(以及发布的所有其他方法)将产生有偏输出。对于大型(-ish)容器,偏差将非常明显。使用合适的。实际上,您可能需要一个允许用户为RNG提供函子的版本。也就是说,libstdc++random_shuffle默认使用rand()%长度,所以我使用了相同的逻辑。@DaveS Eek!是吗?真可怕@康拉德:这不能是:ISO/IEC 14882/2003,25.2.11:“以均匀分布的方式洗牌[第一、最后]范围内的元素”。因此
rand()%n
不能符合标准。只要确保在程序开始时调用
srand()
一次即可。如果在每个
之前调用它
#include <algorithm>
#include <iostream>
#include <random>
#include <vector>

int main() {
    const std::vector<int> in{1, 2, 3, 5, 7};
    std::vector<int> out;
    size_t nelems = 3;
    std::sample(
        in.begin(),
        in.end(),
        std::back_inserter(out),
        nelems,
        std::mt19937{std::random_device{}()}
    );
    for (auto i : out)
        std::cout << i << std::endl;
}
g++-7 -o main -std=c++17 -Wall -Wextra -pedantic main.cpp
./main