最大公约数算法

最大公约数算法分析

看到《编程之美》的最大公约数一节时,理解了一个以前一直不理解的高效GCD算法,此处总结一下。

最大公约数GCD算法中,较为经典的要数《几何原本》里面的辗转相除法,用f(x, y)表示xy的最大公约数,则f(x, y) = f(y, x%y),当y0时返回x。该算法最大的缺陷是需要模运算,对于大数模运算是非常耗时的,模运算本质上是除运算,而除运算可以由基本的加减运算来替代,因此一个改进算法如下:

F(x, y) = f(y, x-y)(x >=yx<y时交换xy位置),这样一直迭代下去,直至其中一个为0,这样避免了耗时的除法运算,但是却引起了过多的迭代运算,对于f(11111111111, 1)这种类型的参数性能较差。

通过分析,可以看出,如果y = k*y1, x = k*x1,那么f(x, y) = k * f(x1, y1),另外如果x = p*x1,p为素数并且y%p != 0,那么f(x, y) = f(p*x1, y) = f(x1, y)。而2就是个素数,并且对于2的乘除操作可以转换为高校的位操作。当p = 2时,

xy均为偶数则 f(x, y) = 2*f(x/2, y/2)

x为偶数则f(x, y) = f(x/2, y)

y为偶数则f(x, y) = f(x, y/2)

xy均为奇数,则x-y为偶数(此处假设x>y)f(x, y) = f(y, x-y)

该思想的一个基本实现如下:

int gcd(int x, int y)

{

if (x < y)

swap (x, y);

if (y == 0)

return x;

   else 

{

if ((x&1) == 0)

{

if ((y&1) == 0)

return gcd(x >>1, y>> 1) << 1;

           else 

return gcd(x >> 1, y);

}

else 

{

if ((y&1) == 0)

return gcd(x, y>> 1);

   else 

return gcd(y, x-y);

}

}

}

该实现是《编程之美》上面给出的,已经比较高效了,但是却采用了递归的形式,对算法性能有一定影响,以前在网上看到一个更为高效的算法,一直没看懂,知道看到书上相关的解析后才恍然大悟,先把代码贴出。

unsigned int gcd(unsigned int x,unsigned int y)   

{   

    unsigned  int  i,j,t;   

    if (x == 0 )  return  y;   

    if (y == 0 )  return  x;   

    for (i = 0 ; 0 == (x & 1 );x >>= 1 , ++ i);  

    for (j = 0 ; 0 == (y & 1 );y >>= 1 , ++ j);   

    for (;;)   

    {   

        if (x < y) t = y,y = x,x = t;   

        if ( 0 == (x -= y))  return  y << i;   

 for (; 0 == (x & 1 );x >>= 1 );   

    }    

在看了书上的算法后,这个算法的思想也较为明了了,首先把xy右移变为奇数(如果他们是偶数的话),较小的移位次数是xy公共操作,可以理解为y = k*y1, x = k*x1f(x, y) = k * f(x1, y1),然后进入for循环,首先保证x >= y,如果x == y,则算法结束,返回y<<i(y*k),否则,由于此时xy都为奇数,且x > y,故x -=  y为偶数,继续将x右移为奇数,相当于书上isEven(x) && isOdd(y)时的处理:return gcd(x >> 1, y)

总体来说两个算法核心思想是一样的,只是后面的算法使用了迭代法,效率高些,在需要高效计算GCD的时候,可以使用上面的算法,特别是在ACM中某些题目需要频繁计算GCD的地方,用时可以有较大的提升。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值