欧几里德算法、扩展欧几里德算法、乘法逆元

转 http://hi.baidu.com/dongxiang2007/blog/item/db9b98626ce722d5e6113a51.html
 
欧几里德算法、扩展欧几里德算法、乘法逆元
2009年05月22日 星期五 下午 12:15

最近看了一本书《程序员》里面说的一个面试题:

求两个数的最大公约数:

SoEasy的题目看过C 的人都知道怎么写这个程序

1.传统方法:穷举

#include
int main()
{
int m=1970,n=1066,p=0;
p=mfor(;p>=1;p--)
{
   Count++;
    if(m%p==0&&n%p==0)
   break;
}
printf("最大公约数是:%d /n",p);
printf("循环了:%d /n",Count);

return 0;
}

最大公约数是:2

循环了:1065次

2.辗转相除

#include
int main()
{
int m=1970,n=1066,p=0;
while(m%n != 0)
{
   p = m%n;
   m = n;
   n = p;
   Count++;
}
printf("最大公约数是%d/n",n);
printf("循环了%d/n",Count);
return 0;
}

最大公约数是:2

循环了:10

对于求1970和1066的最大公约数辗转相除法明显优秀很多。

我们可以将辗转相除法做一个变形。p=m%n 然后将p赋给n实际上就是一个交换 可以写成一个递归的形式如下:

int gcd(int m,int n)

{

      if(n==0)//递归出口

            return m;

      else

             return gcd(n,m%n);

}

这个函数就是传说中的欧几里德算法的描述了。

3.欧几里德算法

#include

int gcd(int m,int n);
int main(int argc, char* argv[])
{
     int m=1970,n=1066;
     printf("最大公约数是:%d/n",gcd(m,n));
     return 0;
}
int gcd(int m,int n)
{
     if(n==0)
     {
         return m;
     }
     else
     {
        return gcd(n,m%n);
      }
}

最大公约数是:2

递归了:10

这个算法基本原理就是辗转相除,效率很高。

在面试的人中大部分都是采用第一种传统的方法。显然面试官想要的是第二种人了。其实从实现的过程来看后者要显得简单一些,递归很好理解。可能是我们都习惯于停用一种算法就解决问题。

4.扩展欧几里德算法

这个算法的并不是为了求最大公约数而设计的,但是它同样可以实现求最大公约数,原理就是Euclid。

扩展欧几里德算主要是解决乘法逆元的问题:A*BModC=1可以将B描述为:A模C的乘法逆元。好了看看算法吧:

int ExGcd(int a, int b, int &x, int &y);

int main(int argc, char* argv[])
{
int m=550,n=1769;
int x=0,y=0;
int k;
k=ExGcd(m,n,x,y);
printf("550 和 1769的最大公约数是:%d/n550模1769的乘法逆元是:%d/n1769模550的乘法逆元是:%d/n",k,x,y);
return 0;
}
/***************************************
函数:ExGcd
功能:求两个数的最大公约数和模P的乘法逆元。
输入:a,b 输入参数,求这两个数的最大公约数
   和a模b的逆元 或 b模a的逆元。
输出:x,y 分别表示a模b的逆元和b模a的逆元。
返回:r 表示a b 的最大公约数。
*************************************/
int ExGcd(int a, int b, int &x, int &y)
{
if(b == 0)
{
   x = 1;
   y = 0;
   return a;
}
int r = ExGcd(b, a % b, x, y);
int t = x;
x = y;
y = t - a / b * y;
return r;
}

程序中有详细的解释。

总结:积累高效算法很重要!

你可能感兴趣的:(欧几里德算法、扩展欧几里德算法、乘法逆元)