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);
}