随机阵列插入的时间复杂度

时间:2015-06-03 14:52:56

标签: arrays algorithm random insert time-complexity

所以我必须以随机顺序将N个元素插入到一个size-N数组中,但我不确定该程序的时间复杂度

该计划基本上是:

for (i = 0 -> n-1){
    index = random (0, n); (n is exclusive)
    while (array[index] != null)
         index = random (0, n);
    array[index] = n
 }

这是我的假设:N个数字的正常插入当然是严格的N,但随机位置的碰撞会花费多少成本?对于每个n,其碰撞率增加如0,1 / n,2 / n .... n-1 / n,因此预期的插入尝试次数将为1,2,3 ... n-1,这是O (n),总时间复杂度为O(n ^ 2),这是平均成本吗?但哇这真的很糟糕,我是对的吗?

那么,如果我进行线性搜索而不是继续尝试生成随机数,会发生什么?最糟糕的情况显然是O(n ^ 2>,但我不知道如何分析其平均情况,这取决于平均输入分布?

2 个答案:

答案 0 :(得分:0)

步骤i中预期的插入次数为

sum_{t=0}^infinity (1-i/n)^t * (n-i)/n * t 
= (n-i)/n * i/n * (1-i/n)^{-2}
= i/(n-i)

总结i得到

sum_{i=0}^{n-1} i/(n-1)
>= sum_{i=n/2}^n i / (n-i) 
>= n/2 sum_{x=1}^n/2 1/x
>= n/2 * log(n) + O(n)

并且

sum_{i=0}^{n-1} i/(n-i)
<= n * sum _{x=1}^n 1/x
<= n * log(n) + O(n)

所以你得到的确是n*log(n)渐近的复杂性。这并不像你担心的那么糟糕。

关于进行线性搜索,我不知道如何在保持数组随机的情况下这样做。如果你真的想要一个有效的算法来改组你的数组,你应该看看Fisher-Yates shuffle。

答案 1 :(得分:0)

首先考虑内循环。当数组中已存在i值时,我们何时能够获得第一次成功(找到未结头寸)?为此,我们使用geometric distribution

Pr(X = k) = (1-p)^{k-1} p

p是尝试成功的概率。 这里p是数组索引尚未填充的概率。 有i个填充位置,因此p = (1 - (i/n)) = ((n - i)/n)

从维基中,对几何分布的期望为1/p = 1 / ((n-i)/n) = n/(n-i)。 因此,当数组中有(n / (n - i))项时,我们应该期望在内循环中进行i次尝试。

要填充数组,我们会在数组中包含i=0..n-1项时插入一个新值。我们期望整体尝试的数量是总和:

sum_{i=0,n-1} n/(n-i)
= n * sum_{i=0,n-1}(1/(n-i))
= n * sum_{i=0,n-1}(1/(n-i))
= n * (1/n + 1/(n-1) + ... + 1/1)
= n * (1/1 + ... + 1/(n-1) + 1/n)
= n * sum_{i=1,n}(1/i)

n的{​​{1}}倍,约为ln(n) + gamma,其中gamma是常量。总的来说,尝试次数约为n * (ln(n) + gamma),即O(nlog n)。请记住,这只是期望,并且由于内部循环是随机的,因此没有真正的上限;它可能永远不会找到一个空位。