给定两个数求它们的最大公约数方法讲解

求两个数的公约数有很多方法,本篇文章介绍2种方法。

方法一:
思路:
我们知道两个数的公约数肯定是小于等于它们之间较小的那个数的,并且这两个数分别取模它们的公约数余数肯定都是0,所以我们可以先确定输入的两个数中哪一个数小一些,然后利用for循环,定义一个变量i,把较小的那个数赋值给i,然后把输入的两个数都取模i,如果两个数取模i余数都为0,那么此时i就为这两个数的最大公约数,当取模不为0时,可以把i的值减小,再来取模,知道得出结果。

代码如下:

#include <stdio.h>
int main()
{
	int a, b;
	scanf("%d%d", &a, &b);				//输入两个数
	int i;
	int min=a;				//首先将其中一个数赋值给min,再判断a和b的大小
	if (b < a)
	{
		min = b;			//如果发现b比a小,就将b赋值给min
	}
	for (i = min; i>0 ; i--)
	{
		if (a % i == 0 && b % i == 0)
		{
			printf("%d\n", i);
			break;
		}
	}
	return 0;
}

这个代码的思路很好想,但是缺点也十分的明显。当a和b的值都很大并且很接近的时候,运算就会十分麻烦。
比如说a=10000,b=9999,它们的最大公约数为1,把9999赋值给i之后,循环就要执行9999次才能结束,虽然也能运行出正确的结果,但会使得代码的效率十分低下

方法二:辗转相除法
思路:
1.将两个整数中较大的数取模较小的数,得到余数。
2.将较小的数替换较大的数,上一步的余数替换较小的数。
3.重复以上步骤,直到余数为0。此时,较小的数即为最大公约数

例如:求21和15的最大公约数
第一次:a = 21 b = 15
c = a % b = 21 % 15 = 6
第二次:a = 15 b = 6
c = a % b = 15 % 6 = 3
第三次:a = 6 b = 3
c = a % b = 6 % 3 = 0
循环结束,此时b中的值(3)即为两个数(21和15)的最大公约数。

这个算法的原理是基于以下定理:两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数

此时很多人应该会疑惑,为什么“两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数“呢?
这个问题涉及辗转相除法的关键思想——“贝祖定理”。
贝祖定理表明,对于任意两个非0整数a和b,存在整数x和y,使得它们满足以下等式:ax+by=gcd(a,b) //(1)
gcd(a,b)表示a和b的最大公约数。

假设商为q,余数为r 可以得到a/b=q……r
我们可以用b来表示a,即a=bq+r //(2)
假设d是a和b的最大公约数,即d=gcd(a,b)
带入(1)式,得到ax+by=d //(3)
将(2)带入(3),得到d=ax+by=(bq+r)x+by=b(qx+y)+rx
qx+y和r都是可以得到的整数,是b和x的系数,所以d也是b和r的公约数。

思路1代码

int c = 0;
c = a % b		//得到余数c

思路2、3代码

//我们肯定是想要把余数替换掉a和b中较大的数,但是在用户还没有输入的时候
//我们不知道是a大还是b大,我们可以假设两种情况:
//(1)a比b大 假如 a=5,b=3 此时c=2
//(2)b比a大 假如 a=3,b=5 此时c=3
//我们可以发现,当a<b的时候,得到的余数肯定是a
//我们肯定更希望用较大的数来除以较小的数,此时假如把b的值赋值给a,把c的值赋值给b
//那么会发现变成了第一种情况,如果再次把b的值赋值给a,把c的值赋值给b,可以发现达到了我们想要的结果,替换掉了最大的数5
//可以用while循环来实现,一直把b和c的值往前面替换,直到余数c=0.
while (c = a % b)	//当余数c=0时,退出循环,此时的b就是a和b的最大公约数
{
	a = b;
	b = c;
}

完整代码如下:

#include <stdio.h>

int main()
{
	int a,b;
	int c = 0;
	scanf("%d%d", &a, &b);
	while (c = a % b)
	{
		a = b;
		b = c;
	}
	printf("gcd(a,b)=%d\n", b);
	return 0;
}

很明显的可以发现,这个程序效率很高,当a,b其中有一个值大于等于2,这样每次循环都会使最大的那个数缩小一半以上(如果a<b,第一次循环不改变值,只是换位置),例如假设a=5,b=2,第一次循环c=1<5/2,一个数除以2得到的余数肯定比自己除以2的值要小。假设a=10000,b=9999,第一次循环c=1,第二次循环就能得出结果,不用像方法一那样循环9999次,极大的提高了程序的效率。

因此,辗转相除法能够很好的提高程序的效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值