所以我必须以随机顺序将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>,但我不知道如何分析其平均情况,这取决于平均输入分布?
答案 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)
。请记住,这只是期望,并且由于内部循环是随机的,因此没有真正的上限;它可能永远不会找到一个空位。