我只能找到关于如何递归和迭代地实现gcd函数的帖子,但是我找不到这个。我确信它在Stackoverflow上然而我找不到它所以我道歉如果它是一个重复的帖子。
我查看了维基百科(here)的分析,无法理解它们的递归关系。
考虑以下在C中递归实现的GCD函数的实现。它具有一个前提条件,即两个数字必须为正,但与运行时无关。
int gcd( int const a, int const b ) {
// Checks pre conditions.
assert( a >= 0 );
assert( b >= 0 );
if ( a < b ) return gcd( b, a );
if ( b == 0 ) return a;
return gcd( b, a % b );
}
对运行时间进行分析我发现每个操作都是O(1),因此我们知道到目前为止的递归关系是:T(n)= O(1)+ ???。现在分析递归调用,我不知道如何将(mod b)解释为我的递归调用以正确陈述我的递归关系。
答案 0 :(得分:7)
在每个递归步骤中,gcd
将其中一个参数减半(最多)。要看到这一点,请看这两种情况:
如果b >= a/2
然后在下一步,您将拥有a' = b
和b' < a/2
,因为%
操作将从{{1}移除b
或更多}}
如果a
然后在下一步,您将拥有b < a/2
和a' = b
,因为b' < a/2
操作最多可以返回%
。
因此,在每个递归步骤中,b - 1
将其中一个参数减半(最多)。这是O(log(N))步骤,其中N是初始gcd
和a
的最大值。
答案 1 :(得分:0)
要分析欧几里德GCD,你应该使用斐波纳契对:gcd(Fib [n],Fib [n - 1]) - 最坏的情况。
如果您测试上面的Euclidean GCD,那么最终会有24个递归调用。
如果您习惯于解决复发关系,您可能会对以下内容感兴趣:
通过这项研究,我们无法推断出任何被除数/除数对的精确迭代次数(因此是小的Oh表示法),但它保证了这个上限是有效的。 通常,下限是Omega(1)(例如,当除数 1 时)。
答案 2 :(得分:0)
一个简单的分析和证据如下:
如果Euclid(a,b)
步数超过N
,则显示
a>=F(n+1)
和b>=F(n)
,其中F(i)
是i
斐波那契
数。
这可以通过Induction轻松完成。
再次显示F(n)
≥φ n-1
诱导。
使用步骤1和2的结果,我们有b≥F(n)
≥
φ n-1
以两侧的对数为准,
log φb≥n-1。
因此证明,n≤1+
日志<子>φ子> B'/ p>
这可以改善这种界限
EUCLID(ka,kb)
中的递归调用次数与EUCLID(a,b)
中的递归调用次数相同,其中k
是一个整数。
因此,边界被改进为1 + log φ(b / gcd(a,b))。