C++ 生成小范围的不同随机数?

C++ 生成小范围的不同随机数?,c++,algorithm,C++,Algorithm,我试图生成一个短范围(大约20个)不同/唯一的随机数 以下是我现在拥有的: 唯一\u random.h: #ifndef UNIQUE_RANDOM_H #define UNIQUE_RANDOM_H // generates a pseudo-random number in [min, max] int random_number (unsigned int min, unsigned int max) { static bool seed_initialized = false;

我试图生成一个短范围(大约20个)不同/唯一的随机数

以下是我现在拥有的:

唯一\u random.h

#ifndef UNIQUE_RANDOM_H
#define UNIQUE_RANDOM_H

// generates a pseudo-random number in [min, max]
int random_number (unsigned int min, unsigned int max) {
    static bool seed_initialized = false;

    if (!seed_initialized) {
        seed_initialized = true;
        srand((unsigned int) time(NULL));
    }

    return rand() % (max - min + 1) + min; 
} 

// generates a random number different from the previously generated
int random_number_without_these (int min, int max, std::set<int>& generated) {
    int res = random_number (min, max);

    // if res one of the previous, generate again
    while (s.find(res) != s.end()) {
        res = random_number (min, max);
    }

    return res;
}

#endif
其中,预期结果是已连续生成20个唯一值。我现在写的东西需要两个函数,
random\u number\u without\u this()
random\u number()
和一个容器,
set
,才能工作,这就是为什么我想知道:

有没有一种更简单的方法来生成短范围的唯一随机数,可能是按照现有代码生成的?

当然可以。如果
(最大-最小)
小到:

#include <iostream>
#include <string>
#include <vector>

std::vector<int> GenUnique(int min, int max, int count) {
  std::vector<int> numbers(max - min + 1), result(count);
  for (int i = 0; i < max - min + 1; ++i) {
    numbers[i] = i + min;
  }
  for (int i = 0; i < count; ++i) {
    int next_index = rand() % (numbers.size());
    result[i] = numbers[next_index];
    numbers[next_index] = numbers.back();
    numbers.pop_back();
  }
  return result;
}

int main()
{
    const auto seq = GenUnique(1, 20, 20);
    for (int elem : seq) {
      std::cout << elem << " ";
    }
    std::cout << std::endl;
}
当然。如果
(最大-最小)
小到:

#include <iostream>
#include <string>
#include <vector>

std::vector<int> GenUnique(int min, int max, int count) {
  std::vector<int> numbers(max - min + 1), result(count);
  for (int i = 0; i < max - min + 1; ++i) {
    numbers[i] = i + min;
  }
  for (int i = 0; i < count; ++i) {
    int next_index = rand() % (numbers.size());
    result[i] = numbers[next_index];
    numbers[next_index] = numbers.back();
    numbers.pop_back();
  }
  return result;
}

int main()
{
    const auto seq = GenUnique(1, 20, 20);
    for (int elem : seq) {
      std::cout << elem << " ";
    }
    std::cout << std::endl;
}
使用和,例如,它实际上非常简单:

#include <iostream>
#include <set>
#include <random>

std::set<int> generate_numbers(const int min, const int max, const int count)
{
    std::set<int> numbers;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(min, max);

    while (numbers.size() < count)
    {
        numbers.insert(dis(gen));
    }

    return numbers;
}

int main()
{
    auto numbers = generate_numbers(1, 20, 20);
    for (auto const v : numbers)
    {
        std::cout << v << ' ';
    }
    std::cout << '\n';
}
#包括
#包括
#包括
std::设置生成_数(最小常数、最大常数、计数常数)
{
std::设置编号;
std::随机_装置rd;
标准:mt19937 gen(rd());
标准:均匀分布图(最小值、最大值);
while(number.size()
#include <iostream>
#include <set>
#include <random>

std::set<int> generate_numbers(const int min, const int max, const int count)
{
    std::set<int> numbers;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<> dis(min, max);

    while (numbers.size() < count)
    {
        numbers.insert(dis(gen));
    }

    return numbers;
}

int main()
{
    auto numbers = generate_numbers(1, 20, 20);
    for (auto const v : numbers)
    {
        std::cout << v << ' ';
    }
    std::cout << '\n';
}
#包括
#包括
#包括
std::设置生成_数(最小常数、最大常数、计数常数)
{
std::设置编号;
std::随机_装置rd;
标准:mt19937 gen(rd());
标准:均匀分布图(最小值、最大值);
while(number.size()std::cout我想推荐这个替代函数。它基本上是来自原始SGI标准模板库的算法。它以统一的概率按顺序生成数字

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

int random_number(int N) // random value in [0, N)
{
    static std::random_device seed;
    static std::mt19937 eng(seed());
    std::uniform_int_distribution<> dist(0, N - 1);
    return dist(eng);
}

std::vector<int> random_sample(int first, int last, int n)
{
    std::vector<int> numbers;
    int remaining = last - first + 1;
    int m = std::min(n, remaining);
    while (m > 0) {
        if (random_number(remaining) < m) {
            numbers.push_back(first);
            --m;
        }
        --remaining;
        ++first;
    }
    return numbers;
}

int main()
{
    auto numbers = random_sample(1, 100, 20);
    for (int value : numbers) {
        std::cout << value << " ";
    }
    std::cout << '\n';
}

#include

我想推荐这个替代函数。它基本上是来自原始SGI标准模板库的算法。它以统一的概率按顺序生成数字

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

int random_number(int N) // random value in [0, N)
{
    static std::random_device seed;
    static std::mt19937 eng(seed());
    std::uniform_int_distribution<> dist(0, N - 1);
    return dist(eng);
}

std::vector<int> random_sample(int first, int last, int n)
{
    std::vector<int> numbers;
    int remaining = last - first + 1;
    int m = std::min(n, remaining);
    while (m > 0) {
        if (random_number(remaining) < m) {
            numbers.push_back(first);
            --m;
        }
        --remaining;
        ++first;
    }
    return numbers;
}

int main()
{
    auto numbers = random_sample(1, 100, 20);
    for (int value : numbers) {
        std::cout << value << " ";
    }
    std::cout << '\n';
}

#include

至于记录,下面是Fisher-Yates Knuth Durstenfeld的一个或多或少忠实的实现,它没有创建源集的显式表示

FYKD的总体思路是从一个序列中均匀取样。所选元素放在序列的末尾,然后继续取样序列减去最后一个元素。冲洗并重复,直到有足够的数字

可以使用可转位生成器模拟序列的这种行为,而无需在内存中创建序列

std::set<long>
rand_unique(const unsigned n, const long max)
{
    std::set<long> selected;

    if (max < 0l) {
        throw std::range_error("max must be >= 0");
    }

    if (n > max) {
        throw std::range_error("too many random numbers requested");
    }

    while (selected.size() < n) {
        long rnd = random() % (max - (long)selected.size());
        if (selected.empty()) {
            /* first number, may even be outside the loop */
            selected.insert(rnd);
        } else {        
            auto it = selected.lower_bound(rnd);
            /* how many numbers are before this one? */
            const long delta = (long)std::distance(selected.begin(), it);
            /**
             * all numbers before the current one have been struck,
             * so shift accordingly by delta
             **/
            rnd += delta;
            /* still a collision? skip over those until a miss */
            while (selected.find(rnd) != selected.end()) {
                rnd += 1l;
            }
            assert(rnd >= 0);
            assert(rnd < max);
            selected.insert(rnd);
        }
    }

    return selected;
}
std::set
rand_unique(常数无符号n,常数最大长)
{
std::选择集合;
如果(最大<0升){
抛出标准::范围_错误(“最大值必须大于等于0”);
}
如果(n>最大值){
抛出std::range_错误(“请求的随机数太多”);
}
while(选定的.size()=0);
断言(rnd
这个函数有一个很好的特性,就是它即使在
n==max
(在
O(mn)
中)也会终止,即
rand_unique(1000,1000)
实际上不需要蒙特卡罗指数时间


由于这有点难以纠正,请随意指出任何剩余的问题。

至于记录,下面是Fisher-Yates Knuth Durstenfeld的一个或多或少忠实的实现,它没有创建源集的显式表示

FYKD的总体思路是从一个序列中均匀取样。所选元素放在序列的末尾,然后继续取样序列减去最后一个元素。冲洗并重复,直到有足够的数字

可以使用可转位生成器模拟序列的这种行为,而无需在内存中创建序列

std::set<long>
rand_unique(const unsigned n, const long max)
{
    std::set<long> selected;

    if (max < 0l) {
        throw std::range_error("max must be >= 0");
    }

    if (n > max) {
        throw std::range_error("too many random numbers requested");
    }

    while (selected.size() < n) {
        long rnd = random() % (max - (long)selected.size());
        if (selected.empty()) {
            /* first number, may even be outside the loop */
            selected.insert(rnd);
        } else {        
            auto it = selected.lower_bound(rnd);
            /* how many numbers are before this one? */
            const long delta = (long)std::distance(selected.begin(), it);
            /**
             * all numbers before the current one have been struck,
             * so shift accordingly by delta
             **/
            rnd += delta;
            /* still a collision? skip over those until a miss */
            while (selected.find(rnd) != selected.end()) {
                rnd += 1l;
            }
            assert(rnd >= 0);
            assert(rnd < max);
            selected.insert(rnd);
        }
    }

    return selected;
}
std::set
rand_unique(常数无符号n,常数最大长)
{
std::选择集合;
如果(最大<0升){
抛出标准::范围_错误(“最大值必须大于等于0”);
}
如果(n>最大值){
抛出std::range_错误(“请求的随机数太多”);
}
while(选定的.size()=0);
断言(rnd
这个有一个很好的特点,它终止于e