使用rand()强制惟一的有效方法是什么?

What is an efficient method to force uniqueness using rand();

本文关键字:有效 方法 是什么 rand 使用      更新时间:2023-10-16

如果我使用(带适当的#includes)

int main()
 {
   srand(time(0));
   int arr[1000];
   for(int i = 0; i < 1000; i++)
      {
        arr[i] = rand() % 100000;
      }
   return 0;
 }

要生成随机的5位ID号(这里忽略omanip的东西),rand()是否保证这些ID号是唯一的?我一直在运行另一个循环来检查数组的所有值与最近生成的ID号,但考虑到嵌套的1000个迭代循环,它需要永远运行。顺便问一下,有什么简单的方法来检查吗?

由于问题标记为c++11,
你应该考虑用<random>代替rand()

使用一个标准的分发引擎,你不能保证你会得到唯一的值。如果你使用的是std::set,你可以一直尝试,直到你有合适的量。根据您的分布范围和您请求的惟一值的数量,这可能就足够了。

例如,下面是一个自定义函数,用于从[x,y]范围中获取n唯一值。

#include <unordered_set>
#include <iostream>
#include <random>
template <typename T>
std::unordered_set<T> GetUniqueNumbers(int amount, T low, T high){
    static std::random_device random_device;
    static std::mt19937 engine{random_device()};
    std::uniform_int_distribution<T> dist(low, high);
    std::unordered_set<T> uniques;
    while (uniques.size() < amount){
      uniques.insert(dist(engine));
    }
    return uniques;
}
int main(){
  //get 10 unique numbers between [0,100]
  auto numbers = GetUniqueNumbers(10,0,100);
  for (auto number: numbers){
    std::cout << number << " ";
  }
}

不能,因为任何对随机源输出的保证都会降低其随机性。

有一些特定的数学公式具有称为随机排列的行为。这个网站似乎有相当好的关于它的文章:http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/

不,绝对不能保证rand不会产生重复的数字,以这种方式设计它不仅要记住它迄今为止返回的所有数字,而且还会大大降低它的随机性(在它返回了许多数字之后,你可以从它迄今为止已经返回的数字中猜测它可能返回的是什么)。

如果惟一性是您的唯一目标,只需为每件事使用一个递增的ID号。如果数字也必须是任意的并且难以猜测,则必须使用某种随机生成器或散列,但应该使数字更长,以使碰撞的机会更接近于0。

然而,如果你绝对必须这样做,我建议将你迄今为止生成的所有数字存储到std::unordered_map中,并生成另一个随机数,如果它已经在其中。

在大多数prng中都有一个通用的唯一性保证,但在这里它对您没有帮助。生成器通常会迭代有限数量的状态,并且不会访问相同的状态两次,直到每个其他状态都访问了一次。

然而,状态和你看到的数字是不一样的。许多状态可以映射到相同的数字,在最坏的情况下,两个连续的状态可以映射到相同的数字。

也就是说,有一些特定的PRNG配置可以在重新访问旧状态之前访问指定范围内的每个值。值得注意的是,如果LCG设计的模量是您的范围的倍数,则可以通过另一次模操作将其缩小到与您的范围完全相同。由于大多数LCG实现具有2次幂周期,这意味着低阶位以较短的周期重复。然而,10000不是2的幂,所以这对你没有帮助。

一个简单的方法是使用LCG,将其位掩码降低到比期望范围大2的幂次,然后丢弃超出范围的结果。