【问题标题】:Random number generation from a vector of numbers从数字向量生成随机数
【发布时间】:2017-11-24 10:29:34
【问题描述】:

我有一个向量v = {1,5,4,2}。现在我想编写一个函数,从这个向量中返回一对随机数字。 示例:{1,2},{4,4},{2,5},{5,1},{1,5},{2,2}.......我希望这对以随机方式生成。 知道如何实现吗?

【问题讨论】:

  • 您需要更具体地定义需求。 (1) 给定[a,b,c]aa 一个可接受的随机对,还是必须是ab、ac 或bc? (2) 我们可以在这个过程中改变向量吗? (3) 性能要求?等
  • 总是返回 v[2] 和 v[4]。请注意,2 和 4 是随机挑选的。

标签: c++ vector random


【解决方案1】:
auto pair = std::make_pair(v[rand() % v.size()], v[rand() % v.size()]);

是一种方式。

如果您需要生成器具有更好的统计属性,则将 rand() 切换到 C++11 的新 <random> 库中的某些内容:除了生成器本身之外,使用 % 可能会引入统计偏差.

【讨论】:

  • 你可以返回相同的元素两次而不是对!在选择第二个随机元素之前,您应该从集合中“排除”第一个元素。
【解决方案2】:

这取决于您是否要保证这两个项目是不同的(即您是否允许将同一个项目绘制两次?)

这是两个要求的解决方案和演示:

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


template<class Rnd, class Iter>
auto random_iterator(Rnd&& rnd, Iter first, Iter last)
{
    assert(first != last);
    std::size_t size = std::distance(first, last);
    auto dist = std::uniform_int_distribution<std::size_t>(0, size - 1);
    auto i = dist(rnd);
    return std::next(first, i);
}

template<class Iter>
auto remove_iter(Iter last, Iter to_remove)
{
    --last;
    std::iter_swap(last, to_remove);
    return last;
}

// precondition: !vec.empty()
template<class Rnd, class T> 
auto select_random_pair(Rnd&& device, std::vector<T> const& vec)
{
    auto first = begin(vec), last = end(vec);

    // care - we are returning references
    auto& a = *random_iterator(device, begin(vec), end(vec));
    auto& b = *random_iterator(device, begin(vec), end(vec));

    return std::tie(a, b);
}

template<class Iter> 
auto make_index_vector(Iter first, Iter last)
{
    auto indices = std::vector<std::size_t>(std::distance(first, last));
    std::iota(begin(indices), end(indices), std::size_t(0));
    return indices;
}

// precondition: vec.size() >= 2
template<class Rnd, class T> 
auto select_distinct_random_pair(Rnd&& device, std::vector<T> const& vec)
{
    auto indices = make_index_vector(begin(vec), end(vec));
    auto first = begin(indices), last = end(indices);

    auto a = *(last = remove_iter(last, random_iterator(device, first, last)));
    auto b = *random_iterator(device, first, last);


    return std::tie(vec[a], vec[b]);
}


int main()
{
    auto test_data = std::vector<int> { 1, 2, 3 };

    auto rng = std::random_device();

    const char* sep = "";
    auto emit = [&sep](std::tuple<int const&, int const&> tup)
    {
        std::cout << sep << "(" << std::get<0>(tup) << ", " << std::get<1>(tup) << ")";
        sep = ", ";
    };

    auto newline = [&sep] { std::cout << '\n'; sep = ""; };

    std::cout << "any:\n";
    for (int i = 0 ; i < 20 ; ++i)
    {
        emit(select_random_pair(rng, test_data));
    }

    newline();

    std::cout << "distinct:\n";
    for (int i = 0 ; i < 20 ; ++i)
    {
        emit(select_distinct_random_pair(rng, test_data));
    }

}

示例输出:

any:
(1, 2), (2, 3), (3, 1), (1, 1), (3, 1), (1, 2), (1, 1), (2, 1), (3, 3), (2, 3), (3, 3), (2, 2), (3, 1), (1, 2), (3, 2), (3, 2), (3, 2), (3, 1), (2, 3), (2, 3)
distinct:
(3, 2), (3, 2), (2, 3), (2, 1), (2, 3), (2, 3), (2, 1), (3, 2), (3, 2), (1, 3), (3, 2), (1, 2), (2, 1), (2, 1), (2, 3), (3, 1), (2, 3), (3, 2), (2, 1), (1, 3)

【讨论】:

  • 您应该为每一对迭代器使用一个模板参数。 firstremove_iter 中未使用。如果您对两个选择使用额外的变量,select_distinct_random_pair 中的扭曲会减少
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
相关资源
最近更新 更多