求两个数的最大公约数

所谓求整数 a、b 的最大公约数,就是求同时满足 a%c=0、b%c=0 的最大正
整数 c,即求能够同时整除 a 和 b 的最大正整数 c。在介绍欧几里得算法之前,
读者可能会有这样的思路:若 a、b 均不为 0,则依次遍历不大于 a(或 b)的所
有正整数,依次试验它是否同时满足两式,并在所有满足两式的正整数中挑选最
大的那个即是所求;若 a、b 其中有一个为 0,那么最大公约数即为 a、b 中非零
的那个;若 a、b 均为 0,则最大公约数不存在(任意数均可同时整除它们)。要
说明的是这个朴素的思路是完全正确的,它的确能够正确的求得两个数的最大公
约数。但是,该解法在大部分情况下要遍历不大于 a(或 b)的所有正整数,并
依次测试它们是否满足条件,当 a 和 b 数值较大时(如 10000000)该算法的时
间复杂度较高,耗费的时间较多,往往不能在指定时间内得到结果。我们试着寻
找一种更加高效的方法来求解最大公约数,首先我们来看如下的证明过程:
若整数 g 为 a、b(不同时为 0)的公约数,则 g 满足:
a= g * l;
b=g * m;
其中 l、m 为整数。同时 a 又可由 b 表示为下式:
a=b * k+ r;
其中 k 为整数,r 为 a 除以 b 后的余数。那么对如上三式做如下变形:
g * l= g * m * k+ r;
r= g * (l?m * k );
由上式可知,a、b 的公约数可以整除 a 除以 b 剩余的余数(记为 a mod b)。
即,a、b 的公约数同时也必是 b、a mod b 的公约数。
那么若 g 是 a、b 的最大公约数,它同样也是 b、a mod b 的最大公约数吗?
我们假设 g 是 a、b 的最大公约数,但它并不是 b、a mod b 的最大公约数,
即存在 g’ > g 且 g’同时整除 b 与 a mod b。这样,必存在整数 l’与 m’使下式成立:
b=g ‘*m’;
r=aModb= g '*l ';
同时 a、b、r 之间满足下式:
a= b * k+ r;
a=g ‘*m’*k+g ‘l ';
a= g '
(m’*k+g '*l ’ ); ( g ‘不等于0)
如上式,g’同时也整除 a,那么 g’同时也是 a、b 的公约数。但是假设中,a、
b 的最大公约数为 g,而 g’>g 与假设不符,所以可证明 a、b 的最大公约数同时
也是 b、a mod b 的最大公约数。
这样,我们把求 a、b 的最大公约数转换成了求 b、a mod b 的最大公约数,
那么问题不变而数据规模则明显变小,我们可以不断重复该过程,直到问题缩小
成求某个非零数与零的最大公约数(该情况一定会发生,证明略)。这样,该非
零数即是所求。
我们来整理一下以上过程:
若 a、b 全为零则它们的最大公约数不存在;若 a、b 其中之一为零,则它们
的最大公约数为 a、b 中非零的那个;若 a、b 都不为零,则使新 a = b;新 b = a %
b 然后重复该过程。
这就是我们要介绍的欧几里得算法,它改变了上文所提到的朴素的枚举算法
需要暴力遍历所有数字的情况,而改为利用数学原理巧妙的将问题转换为规模更
小的问题,从而最后得出答案

#include <stdio.h>
int gcd(int a,int b) {
if (b == 0) return a; //若b为零则最大公约数为a
else return gcd(b,a % b); //否则,则改为求b与a%b的最大公约数
}
int main () {
int a , b;
while (scanf ("%d%d",&a,&b) != EOF) { //输入两个正整数
printf("%d\n",gcd(a,b)); //输出所求的最大公约数
}
return 0;
}

该代码把求最大公约数的欧几里得算法写成了递归的形式,若读者对理解递归有困难,
这里我们也给出其非递归形式,供读者参考。
代码 3.6

#include <stdio.h>
int gcd(int a,int b) {
while(b != 0) { //只要b不为0则一直持续该过程
int t = a % b;
a = b; //使a变成b
b = t; //使b变成a % b
}
return a; //当b为0时,a即是所求
}
int main () {
int a , b;
while (scanf ("%d%d",&a,&b) != EOF) {
printf("%d\n",gcd(a,b));
}
return 0;
}

读者可任意选择递归或者非递归形式的欧几里得算法理解并记忆,这样我们
就已经掌握了求解最大公约数的方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值