自己看相关算法的时候看到求两个数的最大公约数的算法,所以想总结一下关于这方面的知识。
欧几里得算法:欧几里得算法算是求最大公约数最经典的算法,其基于的思想是,对于
gcd(a,b)
,
a>b
,设a,b的最大公约数是d,则:
(1)
r=a−kb
,a能被d整除,b也能被d整除,所以r也能被d整除;
(2)
gcd(a,b)
则可以转化为
gcd(b,r)
,这里
r=a−kb
即就是
a%b
。
该算法可以用递归实现,递归的终止条件是
a%b=0
,其返回值为a,就是最大公约数。
int gcd1(int a, int b){
if(a<b){
int temp = b;
b = a;
a = temp;
}
if(b == 0){
return a;
}
return gcd1(b, a%b);
}
还有一种非递归的写法:
//求最大公约数-欧几里得算法-非递归写法
int gcd2(int a, int b){
if(a<b){
int temp = b;
b = a;
a = temp;
}
while(b != 0){
int temp = b;
b = a%b;
a = temp;
}
return a;
}
尼考曼彻斯法:假设 (a,b) 的最大公约数为T,则假设 a=mT,b=nT ,则a,b不断相减就可以在最后就只剩下一个T,则这个T就是最大公约数。
//尼考曼彻斯法-更相减损法
int gcd3(int a, int b){
if(a<b){
int temp = b;
b = a;
a = temp;
}
while(a - b != 0){
int temp = b;
b = a -b;
a = temp;
}
return a;
}
Stein算法:该算法是建立在以下几个知识点的基础之上
(1)
gcd(a,a)
的最大公约数还是a;
(2)
gcd(ka,kb)=kgcd(a,b)
;
(3)如果a是奇数,b是偶数,
gcd(a,b)=gcd(a,b/2)
,反之亦成立。
int gcd4(int a, int b){
if(a<b){
int temp = b;
b = a;
a = temp;
}
if(0 == b)
return a;
//如果a,b是偶数
if(((a&1) == 0) && ((b&1) == 0)){
return 2*gcd4(a>>1, b>>1);
}
//如果a是偶数,b是奇数
if(((a&1) == 0) && ((b&1) != 0)){
return gcd4(a>>1, b);
}
//如果a是奇数,b是偶数
if(((a&1) != 0) && ((b&1) == 0)){
return gcd4(a, b>>1);
}
//如果a,b是奇数
if(((a&1) != 0) && ((b&1) != 0)){
return gcd4(b, (a - b)>>1);
}
}
还有一种写法:
int gcd(int x,int y)
{
int i,j;
if(x==0) return y;
if(y==0) return x;
for(i=0;0==(x&1);++i)x>>=1; // 去掉所有的2
for(j=0;0==(y&1);++j)y>>=1; // 去掉所有的2
if(j<i) i=j;
while(1){
if(x<y)x^=y,y^=x,x^=y; // 若 x < y 交换 x, y
if(0==(x-=y)) return y<<i; // 若x == y, gcd == x == y (就是在辗转减,while(1)控制)
while(0==(x&1))x>>=1; // 去掉所有的2
}
}