Algorithm 欧几里得的时间复杂性&x27;s算法
我很难确定欧几里得最大公分母算法的时间复杂度是多少。伪代码中的此算法为:Algorithm 欧几里得的时间复杂性&x27;s算法,algorithm,big-o,time-complexity,iteration,Algorithm,Big O,Time Complexity,Iteration,我很难确定欧几里得最大公分母算法的时间复杂度是多少。伪代码中的此算法为: function gcd(a, b) while b ≠ 0 t := b b := a mod b a := t return a 这似乎取决于a和b。我的想法是时间复杂度是O(a%b)。对吗?有没有更好的方法来写呢?网上有一个很好的视角 它甚至有一个很好的值对复杂度图 它不是O(a%b) 众所周知(见文章),它所采取的步骤永远不会超过较小数字中位数的五倍。因此
function gcd(a, b)
while b ≠ 0
t := b
b := a mod b
a := t
return a
这似乎取决于a和b。我的想法是时间复杂度是O(a%b)。对吗?有没有更好的方法来写呢?网上有一个很好的视角 它甚至有一个很好的值对复杂度图 它不是
O(a%b)
众所周知(见文章),它所采取的步骤永远不会超过较小数字中位数的五倍。因此,最大步数随着位数(lnb)
的增加而增加。每一步的成本也随着位数的增加而增加,因此复杂性受O(ln^2b)
的限制,其中b是较小的数字。这是一个上限,实际时间通常较短。请参阅
特别是本部分:
Lamé表明,对于小于n的两个数,求出最大公约数所需的步骤数为
因此,
O(log min(a,b))
是一个很好的上界。欧几里德算法的最坏情况是当余数在每一步都是可能的最大值时,即对于斐波那契序列的两个连续项
当n和m是a和b的位数时,假设n>=m,算法使用O(m)除法
请注意,复杂度总是根据输入的大小给出的,在这种情况下是指位数。分析欧几里德算法时间复杂度的一个技巧是跟踪两次迭代中发生的情况:
a', b' := a % b, b % (a % b)
现在a和b都将减少,而不是只减少一个,这使得分析更容易。您可以将其分为以下几种情况:
现在,我们将展示每种情况都会使总a+b
减少至少四分之一:
- 微小的A:
和b%(A%b)
2a分析算法的合适方法是确定其最坏情况。 当涉及斐波那契对时,欧几里德GCD的最坏情况发生。
,其中i>0 例如,让我们选择股息为55,除数为34的情况(回想一下,我们仍然在处理斐波那契数) 正如您可能注意到的,此操作花费了8次迭代(或递归调用) 让我们试试更大的斐波那契数,即121393和75025。我们在这里也可以注意到,它花费了24次迭代(或递归调用) 您还可以注意到,每次迭代都会产生一个斐波那契数。这就是为什么我们有这么多的行动。我们不能仅仅用斐波那契数得到类似的结果 因此,时间复杂性将由小Oh(上界)表示,这一次。下限直观上是ω(1):例如,500除以2 让我们求解递归关系:void EGCD(fib[i],fib[i-1])
我们可以说,对于迭代算法,欧几里德GCD最多可以进行对数(xy)运算,,,,但是,我们有:
对于斐波那契对,在int iterativeEGCD(long long n, long long m) { long long a; int numberOfIterations = 0; while ( n != 0 ) { a = m; m = n; n = a % n; numberOfIterations ++; } printf("\nIterative GCD iterated %d times.", numberOfIterations); return m; }
和iterativeEGCD()
之间没有区别,后者如下所示:iterativeEGCDForWorstCase()
是的,对于斐波那契对,int iterativeEGCDForWorstCase(long long n, long long m) { long long a; int numberOfIterations = 0; while ( n != 0 ) { a = m; m = n; n = a - n; numberOfIterations ++; } printf("\nIterative GCD iterated %d times.", numberOfIterations); return m; }
和n=a%n
,这是完全一样的 我们还知道,在先前对同一问题的回答中,存在一个普遍的递减因子:n=a-n
因此,为了以定义的形式形成欧几里德GCD的迭代版本,我们可以这样描述为“模拟器”:因子=m/(n%m)
根据Jauhar Ali博士的(最后一张幻灯片),上面的循环是对数的void iterativeGCDSimulator(long long x, long long y) { long long i; double factor = x / (double)(x % y); int numberOfIterations = 0; for ( i = x * y ; i >= 1 ; i = i / factor) { numberOfIterations ++; } printf("\nIterative GCD Simulator iterated %d times.", numberOfIterations); }
是的,很小,因为模拟器最多告诉迭代次数。在欧几里德GCD上探测时,非斐波那契对的迭代次数比斐波那契少。以下是对欧几里德算法运行时复杂性的直观理解。形式证明包含在各种文本中,如算法简介和TAOCP第2卷 首先考虑一下,如果我们试着取两个斐波那契数F(k+1)和F(k)的gcd会怎么样。您可能很快就会发现欧几里德算法迭代到F(k)和F(k-1)。也就是说,在每次迭代中,我们向下移动斐波那契数列中的一个数。由于斐波那契数是O(Phi^k),其中Phi是黄金比率,我们可以看到GCD的运行时间是O(logn),其中n=max(a,b),log以Phi为基数。接下来,我们可以通过观察斐波那契数一致地生成一对,其中余数在每次迭代中保持足够大,并且在序列开始之前永远不会变为零来证明这是最坏的情况
我们可以使O(logn),其中n=max(a,b)的界更紧。假设b>=a,那么我们可以在O(log b)处写入绑定。首先,观察GCD(ka,kb)=GCD(a,b)。由于k的最大值是gcd(a,c),我们可以在运行时将b替换为b/gcd(a,b),从而使O(log b/gcd(a,b))的界限更为严格。Gabriel-Lame定理通过log(1/sqrt(5)*(a+1/2))-2来限制步数,其中日志的基数是(1+sqrt(5))/2。这是针对算法的最坏情况场景,当输入是连续的Fibanocci数时发生 稍微宽松一点的边界是:log A,其中log的基是(sqrt(2))由Koblitz暗示对于密码的目的,我们通常考虑算法的位复杂性,考虑到比特大小近似由k= Loga,
给出。 下面是对欧几里德算法按位复杂性的详细分析: 虽然在大多数参考文献中,欧几里德算法的位复杂度由O(loga)^3给出,但存在一个更紧的界,即O(loga)^2 考虑;r0=a,r1=b,r0=void iterativeGCDSimulator(long long x, long long y) { long long i; double factor = x / (double)(x % y); int numberOfIterations = 0; for ( i = x * y ; i >= 1 ; i = i / factor) { numberOfIterations ++; } printf("\nIterative GCD Simulator iterated %d times.", numberOfIterations); }
unsigned int Gcd(unsigned int M, unsigned int N) { unsigned int Rem; while (N > 0) { Rem = M % N; M = N; N = Rem; } Return M; }
Variables M N Rem initial M N M%N 1 iteration N M%N N%(M%N) 2 iterations M%N N%(M%N) (M%N)%(N%(M%N)) < (M%N)/2