在我的算法课中,我们讨论了摊销复杂性。不幸的是,由于不参加体育比赛,我无法参加。在试图联系教授解释这个失败后,我在这里被问到了。 什么是摊销复杂性?如何找到它? 我被分配了工作但不知道如何去做。如果你们可以帮助我解决一个非常有用的问题,或者提供其他解释的参考。
问题在于:
考虑以下算法并将1添加到二进制数, 表示为n位的数组,假设没有溢出:
increment is
local
i: INTEGER;
do
from i:=n until a.item(i) = 0 loop
a.put(0,i);
i:=i - 1
end;
a.put(1,i)
end
在最坏的情况下,该算法显然是O(n)。显示它的 摊销的复杂性是O(1)。
我可以看出为什么最坏的情况是O(n),但我不知道为什么它的摊销复杂性是O(1)。或者甚至是那种重复的复杂性。
答案 0 :(得分:1)
考虑数字中的实际位如何影响算法将花费多长时间。
时间将在很大程度上取决于数字中最后一个零的位置。因此,'01010111'将比'01010110'花费更多时间来处理,即使它们都具有相同的位数。发生这种情况是因为循环中的停止条件在线性时间内查找最右边的零。
现在,考虑一系列操作,在每次调用时,从数字的末尾开始每个非零位为零。所以下一次执行肯定不会进入循环(因为它将以0结尾)。
摊销的复杂性在预期的一系列操作中寻找平均复杂性。在这种情况下,让我们证明从某个任意数字开始,重复调用increment
将具有平均O(1)复杂度。
让我们调用loop(n)
执行increment
内循环的次数。 loop(n)
是increment
复杂性的主导因素,这是微不足道的。
由此,我们开始争论loop(n) = 0
当且仅当n
是偶数时。这是因为如果n%2 = 0
,则数字中最右边的位为0.这至少每隔2次调用increment
就会发生一次。
我们可以遵循此论点,只有当loop(n) = 1
时才会看到n%4 = 1
。这是因为如果n%4 = 1
,那么n
的最后2位是01
。至少每隔4次调用increment
就会发生这种情况。
使用相同的逻辑loop(n) = 2
当且仅当n%8 = 3
时。这是因为如果n%8 = 3
,那么n
的最后3位是011
。这种情况至少每8次调用increment
就会发生一次。
我们可以概括并说loop(n) = x
当且仅当n % 2^(x+1) = 2^x-1
时。这是因为如果该条件为真,则x+1
的最后n
位为011...11
。每2^(x+1)
次increment
次调用至少发生一次。
要在后续调用loop(n)
后查找increment
的平均值,我们必须根据发生的可能性来衡量可能的成本。
average(loop(n)) = 1/2 + 1/4 + 1/8 + ... = 1
之所以如此,是因为在每2次通话中,一次会有loop(n) = 0
,每4次通话就会有loop(n) = 1
,依此类推......