C ++无重复随机数生成器

时间:2018-01-16 22:01:24

标签: c++ arrays algorithm random permutation

我需要在C ++中创建算法实现,以便为f.e table生成随机数,而不需要重复和列表。

我创建了类似的代码,但是当我在控制台程序中停止工作n = 32769时它停止工作。当我把数字放在0-32768的范围内时,它是有效的。知道这段代码有什么问题吗? 编译时我没有错误/警告。

#include <stdio.h>
#include <iostream>
#include <ctime>


int main()
{
    clock_t start = clock();
    int n;
    std::cout << "n:";
    std::cin >> n;
    bool *used_numbers = new bool[n];
    memset(used_numbers, false, sizeof(used_numbers[0]) * n);
    int *permutation = new int[n];
    srand(unsigned(std::time(NULL)));
     int rnd_number;



    for (int i = 0; i < n; i++)
    {
        rnd_number = rand() % n;
        if (!used_numbers[rnd_number])
        {
            permutation[i] = rnd_number;
            used_numbers[rnd_number] = true;
        }
        else
            i--;
    }
    std::cout << "Permutation: \n ";
    for (int k = 0; k < n; k++)
    {
        std::cout << permutation[k] << " ";
    }
    std::cout << std::endl;

    printf("[Debug]: %lu ms\n", clock() - start);




    getchar();
    system("pause");
    return 0;
}

3 个答案:

答案 0 :(得分:1)

rand() % n

永远不会给你一个大于RAND_MAX的数字。 RAND_MAX是rand()生成的数字的范围。

如果使用大于RAND_MAX的n值,则在绘制第一个RAND_MAX数字后将永远循环。简单地说,没有数字可供绘制。

您需要改进您的解决方案,以便能够生成更大的数字,或者使用更好的东西,例如改组更大的数字列表。

您的算法存在许多问题,但立即进行简单的修复就是:

rnd_number = (rand() * (RAND_MAX + 1) + rand()) % n;

答案 1 :(得分:0)

我只想说明以下问题的其他解决方案,这些问题可能会更快(或者使用更短的代码)(在某些情况下)。

想象一下你需要集合{0,1,...,n - 1}的所有元素的情况,选择最后一个非选择元素的概率(在最后一次迭代中)等于1 / n,预期然后是n次迭代,只选择一个元素。

  1. vector<int> p;
    for(int i = 0; i < n; i++) p.push_back(i);
    random_shuffle(p.begin(), p.end();
    
  2. 然后你可以获取向量p的前K个元素(或整个向量,如果你需要整个排列)。

    1. 在每次迭代中,您可以在1和numbers_left(N - numbers_already_chosen)之间选择一个随机数i,然后选择尚未选择的第i个数字。它也可能效率低下,但是使用一些二进制搜索+二进制索引树,你可以得到O(Nlog ^ 2N),甚至可能更好。

答案 2 :(得分:-2)

如果您需要生成一系列非加密安全数字而不重复,则可以使用Linear-feedback shift register。示例生成65535项(从Wiki采用):

#include <iostream>
#include <set>
#include <cassert>
#include <cstdint>

int main(void)
{
    // Any nonzero start state will work.
    const ::std::uint16_t start_state{0xACE1u};
    ::std::uint16_t lfsr{start_state};
    ::std::uint64_t period{0};
#ifndef NDEBUG
    ::std::set<::std::uint16_t> used_items{};
#endif // #ifndef NDEBUG
    do
    {
        // Get LSB (i.e., the output bit).
        bool lsb{0 != (lfsr & 1)};
        // Shift register
        lfsr >>= 1;
        // If the output bit is 1, apply toggle mask.
        if(lsb)
        {
            lfsr ^= 0xB400u;
        }
        // verify that current value has never appeared before
        assert(used_items.emplace(lfsr).second);
        std::cout << lfsr << "\n";
        ++period;
    }
    while(lfsr != start_state);
    ::std::cout << "period " << period << "\n";
    ::std::cout.flush();
    return 0;
}