📜  当%和/运算成本很高时的Euclid算法

📅  最后修改于: 2021-05-04 15:48:04             🧑  作者: Mango

Euclid算法用于查找两个数字的GCD。

主要有两种算法版本。
版本1(使用减法)

// Recursive function to return gcd of a and b
int gcd(int a, int b)
{
    if (a == b)  
       return a;
   
    return (a > b)? gcd(a-b, b): gcd(a, b-a);
}

版本2(使用模运算符)

// Function to return gcd of a and b
int gcd(int a, int b)
{
    if (a == 0) 
       return b;
      
    return gcd(b%a, a);
}

以上两个中哪个更有效?
版本1可能需要线性时间才能找到GCD,请考虑给定数字之一远大于另一个数字的情况。由于递归调用较少并且花费对数时间,因此版本2显然更有效。

考虑不允许模运算符的情况,我们可以优化版本1使其工作更快吗?

以下是一些重要的观察。这个想法是使用按位运算运算符。我们可以使用x >> 1来找到x / 2。我们可以使用x&1来检查x是奇数还是偶数。

如果a和b均为偶数,则gcd(a,b)= 2 * gcd(a / 2,b / 2)。
如果a为偶数且b为奇数,则gcd(a,b)= gcd(a / 2,b)。
如果a为奇数而b为偶数,则gcd(a,b)= gcd(a,b / 2)。

下面是C++的实现。

// Efficient C++ program when % and / are not allowed
int gcd(int a, int b)
{
    // Base cases
    if (b == 0 || a == b) return a;
    if (a == 0) return b;
  
    // If both a and b are even, divide both a
    // and b by 2.  And multiply the result with 2
    if ( (a & 1) == 0 && (b & 1) == 0 )
       return gcd(a>>1, b>>1) << 1;
  
    // If a is even and b is odd, divide a by 2
    if ( (a & 1) == 0 && (b & 1) != 0 )
       return gcd(a>>1, b);
  
    // If a is odd and b is even, divide b by 2
    if ( (a & 1) != 0 && (b & 1) == 0 )
       return gcd(a, b>>1);
  
    // If both are odd, then apply normal subtraction 
    // algorithm.  Note that odd-odd case always 
    // converts odd-even case after one recursion
    return (a > b)? gcd(a-b, b): gcd(a, b-a);
}