您的位置:首页 > 其它

求最大公约数

2017-09-14 20:15 239 查看
本文主要归纳了求最大公约数的几种方法,包括遍历法、欧几里得算法、 Stein算法等。

遍历法

这是一种比较直接、简单的方法。思路是:从两个数中选取一个较小的数作为遍历的起点,然后逐步减去1,寻找可能同时被两个数整除的约数。具体实现如下:

int traverse_Gcd(int n,int m){
int i=n>m?m:n;
for(;i>=1;i--){
if(n%i==0 && m%i==0){
return i;
}
}
}


欧几里得算法

欧几里得算法,又称为辗转相除法。其应用的原理是:

Gcd(a,b)=Gcd(b,a%b);

解析:

因为 a%b=a-(a/b)*b (1)

所以 假设a,b的一个公约数为c,那么有a%c==0,b%c==0;

我们把(1)式等号右边的式子,由减号分割为两部分,第一部分是a ,显然可以整除c;第二部分是(a/b)*b,因为b可以整除c,所以b与另外一个数的乘积依旧可以整除c,所以(a/b) *b 可以整除b。由此可以说明,a和b的最大公约数与b和a%b的最大公约数相同,以上式子成立。

以下给出欧几里得算法的递归实现:

int Euclidean_GCd(int n,int m){
if(m==0){
return n;
}
Euclidean_GCd(m,n%m);

}


以下给出欧几里得算法的迭代实现:

int Euclidean2_GCd(int n,int m){

if(m==0){
return n;
}

while(m!=0){
int t=m;
m=n%m;
n=t;

}
return n;

}


扩展的欧几里得算法

已知整数n、m,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y(其中一个很可能是负数),使它们满足贝祖等式:

nx + my = Gcd(n, m); (1)

由(1)式可得 , n’ x + m’ y = Gcd (n’,m’); (2)

又 n’ = m;

m’ = n % m = n - (n/m)* m;

把n’ 和 m’ 代入 (2)式得

m x + [ n - (n/m)*m ] y= Gcd (n’,m’);

整理得

ny + m (x- (n/m)y)=Gcd (n’,m’);

故 x’ = y;

y’ = x-(n/m)y;

代码如下:

int Extended_Euclidean_GCd(int n,int m,int* x,int* y){
if(m==0){
*x=1;
*y=0;
return n;
}else{
int r= Extended_Euclidean_GCd(m,n%m,x,y);
int t= *x;
*x = *y;
*y = t - (n/m)* *y;
return r;
}
}


欧几里得算法采用的是辗转相除的方法,在一般情况下效率比较高。但是当在处理大整数时,由于除法运算的存在,该算法的效率大受影响。

Stein算法

采用移位和减的方式来处理数据,没有除法运算,所以在求最大公约数时是比较高效。

Stein算法原理如下:

1.若a和b都是偶数,则记录下公约数2,然后都除2(即右移1位);

2.若其中一个数是偶数,则偶数除2,因为此时2不可能是这两个数的公约数了

3.若两个都是奇数,则a = |a-b|,b = min(a,b),因为若d是a和b的公约数,那么d也是a-b和min(a,b)的公约数。

基于以上的原理,递归算法实现如下:

int Stein_Gcd(int a,int b){
int t;
if(a < b){
t = a;
a = b;
b = t;
}
if(b == 0)
return a;
if(a%2==0 && b%2==0){
return 2*Stein_Gcd(a/2,b/2);
}else if(a%2==0 && b%2!=0){
return Stein_Gcd(a/2,b);
}else if(a%2!=0 && b%2==0){
return Stein_Gcd(a,b/2);
}else {
return Stein_Gcd(a-b,b);
}

}


参考链接:

https://www.cnblogs.com/drizzlecrj/archive/2007/09/14/892340.html

http://blog.csdn.net/workformywork/article/details/16368345
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息