找出之前是否发生过随机数

时间:2012-12-10 13:22:48

标签: algorithm random-sample

首先让我说清楚这是一个人为的例子而不是现实世界的问题。

如果我有一个在0到10之间创建一个随机数的问题。我这样做了11次,确保先前发生的数字不再被绘制,如果我得到一个重复的数字, 我再次创建另一个随机数,以确保它之前没有被看到。所以基本上我以随机顺序从0到10得到一系列唯一数字 例如3 1 2 0 5 9 4 8 10 6 7等等

现在提出逻辑以确保随机数是唯一的而不是我们之前绘制的,我们可以使用很多方法

使用C ++ std::bitset并将与索引对应的位设置为等于每个随机数的值。并在下次绘制新的随机数时检查它。

使用std::map<int,int>来计算存储在该数组中的一些标记值的简单C数组甚至是简单的C数组,以指示该数字是否已经发生。

如果我必须避免上面的这些方法,并使用一些数学/逻辑/按位运算来查找是否已经绘制了随机数,是否有办法?

5 个答案:

答案 0 :(得分:3)

你不想按照你的建议去做。考虑当你已经选择了11个项目中的10个时会发生什么;您的随机数生成器将循环,直到找到丢失的数字,这可能永远不会,这取决于您的随机数生成器。

更好的解决方案是按顺序创建数字0到10的列表,然后将列表随机排序。执行此操作的常规算法是由于Knuth,Fisher和Yates:从第一个元素开始,使用大于数组中当前元素的位置处的元素交换每个元素。

function shuffle(a, n)
    for i from n-1 to 1 step -1
        j = randint(i)
        swap(a[i], a[j])

我们假设一个索引为0到n-1的数组,以及一个randint函数,它将j设置为0 <= j&lt; = i。

答案 1 :(得分:1)

使用数组并向其添加所有可能的值。然后从阵列中挑出一个并将其移除。下次再次选择,直到数组为空。

答案 2 :(得分:1)

是的,有一种数学方式可以做到这一点,但它有点广泛。

有一个数组:primes[]其中primes[i] = the i'th prime number。所以它的开头是[2,3,5,7,11,...]

同时存储一个号码mult现在,一旦你绘制了一个数字(让它为i),你检查mult % primes[i] == 0是否为mult = mult * primes[i] - 之前是否绘制了数字,如果是不是 - 然后数字不是。选择它并做mult

然而,它是广泛的,因为它可能需要大量空间用于大范围(p_i的可能值以指数方式增加

(这是一个很好的数学方法,因为我们实际上看一组素数int,素数数组只是对素数抽象集的实现。)


小值的位操作替代方法是使用longi作为位集。

通过这种方法,检查候选人set不在if (pow(2,i) & set == 0) // not in the set else //already in the set 中,您只需要检查:

i

在集合中输入元素set = set | pow(2,i)

list

更好的方法是使用所有数字填充{{1}},将其与fisher-yates shuffle混合,并迭代它以生成新的随机数。

答案 3 :(得分:0)

  

如果我必须避免使用上述方法并使用一些方法   数学/逻辑/按位运算,以查找是否为随机数   以前是不是有吸引力,是否有办法?

根据您的设计约束条件,您可以使用按位运算模拟​​一个小位集:

您可以根据需要选择不同的整数类型。

bitset code                    bitwise code

std::bitset<32> x;             unsigned long x = 0;
if (x[i]) { ... }              if (x & (1UL << i)) { ... }
// assuming v is 0 or 1
x[i] = v;                      x = (x & ~(1UL << i)) | ((unsigned long)v << i);
x[i] = true;                   x |= (1UL << i);
x[i] = false;                  x &= ~(1UL << i);

对于更大的集合(超出unsigned long long的位大小),您将需要一个所选整数类型的数组。将索引除以每个值的宽度,以了解要在数组中查找的索引,并使用模数进行位移。这基本上是bitset的作用。

我假设各种答案告诉你如何最好地改变10个数字完全忽略了这一点:你的设计约束是因为你实际上并不想要或者需要知道如何最好地改组10个数字: - )

答案 4 :(得分:0)

保持变量也会映射绘制的数字。如果在之前绘制数字,该变量的第i位将为1:

int mapNumbers = 0;

int generateRand() {        
    if (mapNumbers & ((1 << 11) - 1) == ((1 << 11) - 1)) return; // return if all numbers have been generated
    int x;  
    do {
        x = newVal();
    } while (!x & mapNumbers);
    mapNumbers |= (1 << x);
    return x;
}
相关问题