两个数的最大公约数

来源:互联网 发布:中小学生网络作文大赛 编辑:程序博客网 时间:2024/05/16 10:40

笔试面试题目中经常会遇到两个数最大公约数的问题,一种比较流行的方法是,用较大者除以较小者,若整除,较小者为最大公约数,若有余数,则求余数与较小者的最大公约数,递归实现。它是基于这样一个事实,即若x = k*m;y=k*n;那么y/x = n/m; y%x = k*(m%n);即x和y%x也有最大公约数k.这种方法很容易编程实现,但是一个不足时计算机计算取模运算相当于除法,很耗时间,于是有了进一步改进。

版本一:

int gcd_ver_1(int x, int y){    if (x > y)        return gcd_ver_1(y, x);            int mod = y%x;    if (!mod)        return x;    else        return gcd_ver_1(x, mod);}

此版本采用尾递归的形式,因此可以化为循环。


同样地,我们发现y-x = k*(n-m),于是x和y-x也有公约数k,这样就可以用加减法替代取模运算,性能有所提高。

版本二:

int gcd_ver_2(int x, int y){    if (x > y)        return gcd_ver_1(y, x);    if (!x)        return y;    else        return gcd_ver_2(x, y-x);}


但是这样也有个问题,如果数值太大,循环进行的次数比较多,而第一种方法呢,虽然循环次数少,但是有取模运算,能不能把两者结合起来呢。

我们发现,如果一个素数p,即是x的约数又是y的约数,那么,f(x,y) = p*f(x/p,y/p);

如果一个素数p,仅仅是x的约数,由于它是素数,所以,f(x,y) = f(x/p, y);同理,y也一样。

那么,考虑到2是一个素数,况且计算机对2的运算可以变为位运算,所以取p=2;

如果x,y均为偶数,那么f(x,y) = 2 * f(x>>1, y>>1)

如果x为偶数,y为奇数,那么f(x,y) = f(x>>1, y)

如果y为偶数,x为奇数,那么f(x,y) = f(x, y>>1)

如果x、y均为奇数,那么用第二个版本的逻辑,f(x,y) = f(x, y-x);不管是x-y还是y-x,必定有一个数是偶数,那么就可以回归上面的几步了。

int gcd_ver_3(int x, int y){    if (x > y)        return gcd_ver_3(y ,x);    if (!x)        return y;    else {        if (!(y & 0x1)) {            if (!(x & 0x1))                return (gcd_ver_3(x>>1, y>>1)) << 1;            else                return gcd_ver_3(x, y>>1);        }        else {            if (!(x & 0x1))                return (gcd_ver_3(x>>1, y));            else                return gcd_ver_3(x,y-x);        }    }}


摘自《编程之美——最大公约数》

原创粉丝点击