我正在通过sedgewick对quick-union algorithm
一书Algorithms 4th ed
进行分析。作者给出了这段代码和评论
...
for(int i =0; i< N; i++){
id[i] = i;
}
...
private int find(int p){
while(p != id[p]){
p = id[p];
}
return p;
}
public void union(int p, int q) {
int proot = find(p);
int qroot = find(q);
if (proot == qroot){
return;
}
id[proot] = qroot;
this.count--;
}
考虑最坏的情况,其中p,q对(0,1),(0,2),(0,3),(0,4)等被赋予union()
。 union()
对0,i
的数组访问次数正好是2i+3
(注意:在书中它打印为2i + 2,但勘误表示为2i + 3)。site 0 at at深度i和网站i的深度为0。
我试图为调用union(0,1)
解决这个问题这涉及两个find()
调用(0和1作为输入)和数组修改id[proot]= qroot
考虑find(0)
数组id []为0,1,2,3,4..
在while循环中,p = 0
test 0!= id [0]失败,因为id [0] = 0。因此,find(0)中只有1个数组访问
在find(1)中,test 1!= id [1]失败,因此find(1)只进行1次数组访问。
然后id [proot] = qroot只导致1个数组访问。
总共有3个数组访问。
但是当使用等式时,使用2i + 3(对于对(0,i))
对(0,1)的数组访问次数 - &gt; 2 * 1 + 3 = 5
我很困惑..有人能告诉我我的错误吗?
答案 0 :(得分:1)
我的分析似乎同意你的观点,原始解决方案和勘误表都是错误的。我的主张是假设调用模式为2(i-1) + 3
,union(0, i)
将union(0, 1), union(0, 2), ..., union(0, i)
数组访问。我们可以通过归纳来证明这一点。
特别是我们证明了一个更强有力的主张,即union(0, i)
需要2(i-1 + 3
数组访问和 id
数组看起来像1, 2, 3, ..., k-2, k, k, k+1, ..., N
在k
union()
之后。更强烈的声明使感应清洁。
在基本情况下,正如您所观察到的,union(0, 1)
有三个数组访问。此时,通过检查,我们有一个看起来像[1, 1, 2, ..., N]
的数组。在归纳步骤中,我们假设声明适用于1 <= j <= k
,并考虑id
开头的union(0, k+1)
数组的状态。此时它看起来像
[1, 2, 3, ..., k-2, k, k, k+1, ..., N]
通过归纳假设。在这一点上通过检查,我们有我们的主张。特别是,find(0)
将进行2(k + 1 - 1)
数组访问。 find(k+1)
将需要两个。 id[0] = k+1
的分配是最后一个根据需要提供给我们2((k + 1) - 1) + 2 + 1 => 2((k + 1) - 1) + 3
的。请注意,该数组也将变为
[1, 2, 3, ..., k-2, k-1, k+1, k+1, k+2, ..., N]
因为我们需要感应。
你在关于这个Theta(n^2)
的评论中提到的后一部分来自某些代数。特别是让f(n)
成为调用union(0, 1), union(0, 2), ..., union(0, n)
的数组访问次数,其中n < N
是数组的大小。然后,上述声明显示f(n) - f(n-1) = 2(n - 1) + 1
和f(1) = 3
(我们的基本情况)。那我们就有了
f(n) = f(n) - f(n-1) +
(f(n-1) - f(n-2)) +
(f(n-2) - f(n-3)) +
... +
(f(2) - f(1)) +
f(1)
=>
f(n) = 2(n-1) + 3 +
2(n-2) + 3 +
2(n-3) + 3 +
... +
2(1) + 3 +
2(0) + 3
=>
f(n) = Sum(2(i-1) + 3) from i = 1 to i = n
第一步是因为它“望远镜”并且通过检查是真实的。计算算术,这样的有限进展有一个很好的技巧。添加第一个和最后一个元素,然后添加第二个和倒数第二个元素,依此类推。你会注意到它们都是一样的,并且可以证明它们是一样的。我会让你搞砸了,但封闭的形式是
n^2 + 2
显示Theta(n^2)
是一个“留给读者的练习”嘿。如果一切都失败了,你应该在教科书中看到相同的证据。
哦,我在评论中提到,即使它是2i+2
或2i+3
,上述证据也不会真正改变那么多。绝对花时间问这个问题,但不是几个小时......特别是如果你对你的答案有信心(通过证明我在这里做的,或在你脑海中勾勒出证据)。几乎可以肯定的是,除非1是非常重要的(有一些基本情况实际上很难看出为什么他们有一定的价值!花时间知道为什么它是0而不是1可能是有价值的),所以你必须做出自己的判断。祝你好运