早在公元前300年左右,
欧几里得就在他的著作《
几何原本》中给出了高效的解法——辗转相除法。
辗转相除法使用到的原理很聪明也很简单,假设用f(x, y)表示x,y的最大
公约数,取k = x/y,b = x%y,则x = ky + b,如果一个数能够同时
整除x和y,则必能同时整除b和y;而能够同时整除b和y的数也必能同时整除x和y,即x和y的公约数与b和y的公约数是相同的,其最大公约数也是相同的,则有f(x, y)= f(y, x % y)(y > 0),如此便可把原问题转化为求两个更
小数的最大公约数,直到其中一个数为0,剩下的另外一个数就是两者最大的公约数。
证明如下:
我们只需证明
gcd(a,b)和
gcd(b,a%b)可以互相整除即可。
对于gcd(a,b),它是a和b的线性组合中的最小正元素,gcd(b,a%b) 是b与a%b的一个
线性组合,而a%b是a与b的一个线性组合,因而gcd(b,a%b)是一个a与b的线性组合,因为a,b都能被gcd(a,b)整除,因而任何一个a与b的线性组合都能被gcd(a,b)
整除,所以gcd(b,a%b)能被gcd(a,b)整除。反之亦然。
(摘自百度百科)
这都是网上比较正式比较权威的解释,直接就拿来用了。
下面是我写的一段代码,还有注释中是三种摘自网络上别人的不同解法。人家的代码简直精简到一塌糊涂。~~~~(>_<)~~~~
#include<stdio.h> /*欧几里得算法(辗转相除法)求最大公约数。*/
int gcd(int m,int n);
int main (void){
int m,n;
printf("请输入m和n的数值(都为正整数),将为你求出两个数的最大公约数:\n");
scanf("%d %d",&m,&n);
printf("%d\n",gcd(m,n));
return 0;
}
int gcd(int m,int n){ //我的递归法
if(n==0)
return m;
return gcd(n,m%n);
}
int gcd(int a,int b) //精简版递归法
{
return (b>0)?gcd(b,a%b):a;
}
/*int gcd(int a,int b) //位运算法。这个代码害怕不害怕。。
{
while(b^=a^=b^=a%=b);
return a;
} */
话说看到位运算法的时候真被吓到了。。确实非常精炼!
下面把这句提取出来,小小的分析一下。
while(b^=a^=b^=a%=b);
因为两个数字进行三次异或运算可以交换数值。
while(b>0){
a=a%b; -->求出余数赋给a;
b=b^a; -->通过亦或运算,b的值变为其他值
a=a^b; -->a的值变为原b的值
b=b^a; -->b的值变为原a的值
}
return a;
这样,当b为0的时候,a就是最大公约数,然后返回这个值即可:
还有一种方法叫二进制gcd法