什么是使用随机数生成器的代码的大O?

时间:2016-10-03 02:07:08

标签: c++ algorithm big-o

我想用从1到N的随机值填充数组'a'(没有重复的值)。让我们假设randInt(i,j)的Big-O是O(1),这个函数从i到j生成随机值。
输出的例子是:

{1,2,3,4,5}或{2,3,1,4,5}或{5,4,2,1,3}但不是{1,2,1,3,4 }

#include<set>
using std::set;

set<int> S;// space O(N) ?
int a[N];  // space O(N)
int i = 0; // space O(1)
do {
    int val = randInt(1,N);   //space O(1), time O(1) variable val is created many times ?
    if (S.find(val) != S.end()) { //time O(log N)? 
        a[i] = val; // time O(1)
        i++; // time O(1)
        S.insert(val); // time O(log N)  <-- we execute N times O(N log N)
    }
 } while(S.size() < N); // time O(1)

While循环将继续,直到我们生成从1到N的所有值。 我的理解是,Set以对数时间日志(N)对值进行排序,并在log(N)中插入。

Big-O = O(1) + O(X*log N) + O(N*log N) = O(X*log N) 

其中X越多,生成不在Set中的数字的概率很高。

time O(X log N)

space O(2N+1) => O(N), we reuse the space of val 

??每次执行randInt时都很难生成所有不同的数字,所以至少我希望执行N次 变量X是多次创建的?
什么是X的好价值?

3 个答案:

答案 0 :(得分:3)

假设RNG是理想的。也就是说,重复调用randInt(1,N)会生成i.i.d. (独立且相同分布的)值序列均匀分布在{1,...,N}上。

(当然,实际上RNG并不理想。但是让我们继续使用它,因为它使数学更容易。)

平均情况

在第一次迭代中,选择了一个随机值val 1 ,当然它还不在集合S中。

在下一次迭代中,选择另一个随机值。

  • 使用概率(N-1)/ N,它将与val 1 不同,并且将执行内部条件。在这种情况下,调用所选值val 2
  • 否则(概率为1 / N),所选值将等于val 1 。重试。

在选择有效(不同于val 1 )val 2 之前,平均需要多少次迭代?好吧,我们有一个独立的尝试序列,每个尝试都以概​​率(N-1)/ N成功,我们想知道在第一次成功之前平均需要多少次尝试。这是几何分布,并且通常具有成功概率p的几何分布具有平均值1 / p。因此,平均需要N /(N-1)次尝试选择val 2

类似地,平均需要N /(N-2)次尝试选择与 1 和val 2 不同的val 3 ,等等。最后,第N个值平均需要N / 1 = N次尝试。

总的来说,do循环将被执行

1 + N/(N-1) + N/(N-2) + ... + N/1 = N sum_{i=1}^N 1/i

平均次数。总和sum_{i=1}^N 1/i是第N harmonic number,其可以大致近似为ln(N)。 (有一个众所周知的better approximation,它有点复杂,涉及Euler-Mascheroni constant,但ln(N)足以找到渐近的复杂性。)

因此,对于近似值,平均迭代次数将为N ln N.

算法的其余部分怎么样?将N个东西插入集合中的事情也最多需要O(N log N)时间,因此可以忽略不计。剩下的最重要的事情就是每次迭代你必须检查所选择的随机值是否位于S中,这取S的当前大小的对数时间。所以我们必须计算

N sum_{i=1}^N ln(i) / i

从数值实验来看,对于大N来说,似乎大约等于N / 2 *(ln N)^ 2. (考虑在math.SE上要求证明这一点。)编辑:请参阅this math.SE answer获取简短的非正式证明,并other answer to that question获取更正式的证据。

总之,总平均复杂度为Θ(N(ln N)^ 2)。 同样,这是假设RNG是理想的。

最坏情况

与xaxxon提到的一样,原则上(尽管不太可能)算法根本不会终止。因此,最坏情况的复杂性将是O(∞)。

答案 1 :(得分:0)

这是实现目标的非常糟糕的算法。

只需用数字1到N填充数组,然后随机播放。

那是O(N)

https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle

要进行随机播放,请选择介于0和N-1之间的索引并将其与索引0交换。然后选择介于1和N-1之间的索引并将其与索引1交换。一直到列表结尾。< / p>

就具体问题而言,它取决于随机数生成器的行为。如果它真的是随机的,它可能永远不会完成。如果它是伪随机的,则取决于发生器的周期。如果它的周期为5,那么你永远不会有任何欺骗行为。

答案 2 :(得分:-2)

具有复杂行为的灾难性代码。生成第一个数字是O(1),然后第二个数字涉及二进制搜索,因此日志N加上生成器的重新运行应该找到数字。获得新数字的机会是p = 1- i / N.因此,平均重新运行次数是倒数,并给出另一个因子N.所以O(N ^ 2 log N)。

这样做的方法是生成数字,然后将它们洗牌。那是O(N)。