《编程之美》笔记2 最大公约数

求两个正整数的最大公约数?

 设要求x,y(x>y)的最大公约数,并且有 x = k*y+b.——   x % y = b

 

解法一:辗转相除法

 一个基本的方法就是辗转相除法:x与y的最大公约数就是y和b的最大公约数。算法不断递归进行,直到b的值为0,此时y的值就是最大公约数。

  使用递归方法:

  int gcd(int x, int y)
  {     
if(x < y)       return gcd(y, x);     if(y <= 0)       return x;     return gcd(y, x%y);   }

 使用迭代方法:

int gcd(int x, int y)
{
    if(x < y)
        {int temp = x; x = y; y = temp}
    while(y != 0)
    {
        int temp = x % y;
        x = y;
        y = temp; 
    }
    return x;
}

解法二:
  取模运算的开销很大,可以采用减法来去掉取模运算,就是“《编程珠玑》第九章代码调优”的内容。

  因为 m = x % y 就等价于

  m = x-y;

  while(m >= y)

    m = m-y;

  所以对于求最大公约数,直接将递归方法中的 return gcd(y, x%y); 变为 return gcd(x-y, y);就完了。

  该方法的缺点就是迭代次数会变得很大。特别是x与y相差较大时。

解法三:

  分析公约数的特点:

  对x和y,若 y = k * y1, x = k * x1; 那么,f(x, y) = k * f(x1, y1).

      另外,若x = p * x1,假设p是素数,并且 y%p != 0,(即y不能被p整除)那么f(x,y) = f(p*x1, y) = f(x1, y).

  所以我们在此处假设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>>1)

  若x和y均为奇数,f(x,y) = f(y, x-y),这样x-y必定为偶数,下一步可以除以2进行缩小。

  代码如下:

int gcd(int x, int y)
{
    if(x < y)
        return gcd(y, x);
    if(y == 0)
        return x;
    if(isEven(x))
    {
        if(isEven(y))
            return gcd(x>>1, y>>1) << 1;
        else
            return gcd(x>>1, y);
    }else{
        if(isEven(y))
            return gcd(x, y>>1);
         else
            return gcd(y, x-y);
    }
}

 

 

posted @ 2012-09-12 23:14  dandingyy  阅读(301)  评论(0编辑  收藏  举报