题目:求最大公约数
用辗转相除法求最大公约数的解法相信大家都很熟悉,就是用大数除以小数,然后取出余数与之前较小的数再递归地进行同样的操作,直到其中一个数为0。
但是这样的除法在遇到大整数的时候作除法非常地耗时,这样对效率方面有很大的影响。
设两个数为x,y
采用辗转相除法的分析,如果一个数能够同时正处x和y,则必能同时整除x-y和y;而能够同时整除x-y和y的数也必能同时整除x和y,即x和y的公约数与x-y与y的公约数是相同的,其最大公约数也是相同的,即f(x,y)=f(x-y,y),那么就可以不再需要进行大整数的取模运算,而转换成简单得多的大整数减法。
但是,如果遇到大整数的时候,要做减法就要进行很多次迭代,所以还有改进的地方。
接下来分析公约数的特点:
对于y和x来说,如果y=k*y1,x=k*x1。那么有f(y,x) = k*f(y1,x1)
如果x=p*x,假设p是素数,并且y%p!=0,那么f(x,y)=f(p*x1,y)=f(x1,y)
我们还知道2是一个素数,而且对于大整数而言,可以很容易地将除以2/乘以2的运算转换成移位运算,从而避免了大整数除法,以下做分析:
p=2
若x,y均为偶数,f(x,y) = 2*f(x/2, y/2) = 2*f(x>>1, y>>1)
若x为偶数,y为奇数,f(x,y) = f(x/2, y) = f(x>>1, y)
若x为奇数,y为偶数,f(x,y)=f(x,y/2)=f(x,y>>1)
若x,y均为奇数,f(x,y)=f(y, x-y),那么x-y就是一个偶数,所以下一步递归一定会有除以2的操作。
算法伪代码:
/*
*count max common divisor
*/
int mcd(int x, int y)
if x < y
then return mcd(y, x)
else if y == 0
then return x
if x is even
if x is even && y is even
//x >> 1 equals x/2
then return (mcd(x >> 1, y >> 1) >> 1)
else return mcd(x >> 1, y)
if x is not even && y is even
then return mcd(x, y >> 1)
else return mcd(y, x-y)
C++实现
int mcd(int x, int y)
{
//if x < y
if(x < y)
{
//then return mcd(y, x)
return mcd(y, x);
}//else if y == 0
else if(y == 0)
{
//then return x
return x;
}
else
{
//if x is even
if(isEven(x))
{
//if x is even && y is even
if(isEven(y))
{
//x >> 1 equals x/2
//return (mcd(x >> 1, y >> 1) >> 1)
return (mcd(x >> 1, y >> 1) << 1);
}
else
{
//else return mcd(x >> 1, y)
return mcd(x >> 1, y);
}
}
else
{
//if x is not even && y is even
if(isEven(y))
{
//then return mcd(x, y >> 1)
return mcd(x, y >> 1);
}
else
{
//else return mcd(y, x-y)
return mcd(y, x-y);
}
}
}
}