C:求两个数的最大公约数详解(硬核算法,辗转相除法,更相减损法)

583 阅读2分钟

最大公因数,也称最大公约数、最大公因子。

定义:
指两个或多个整数共有约数中最大的一个。

a,b的最大公约数 记为(a,b),同样的,a,b,c的最大公约数记为(a,b,c),多个整数的最大公约数也有同样的记号。
求最大公约数有多种方法,常见的有质因数分解法、短除法、辗转相除法、更相减损法。与最大公约数相对应的概念是最小公倍数,a,b的最小公倍数记为[a,b]。

解法一:最普通的算法(十分硬核)
程序代码:

int main()
{
	int i, a, b;
	int max = 1, min;

	printf("请输入两个数:");
	scanf("%d%d", &a, &b);
	if (a > b)	//判断输入两个个数的大小
	{
		min = b;
	}
	else
	{
		min = a;
	}
	for (i = 2; i <= min; i++)
	{
		if (a%i == 0 && b%i == 0)
		{
			max = i;
		}
		else
		{
			continue;
		}
	}
	printf("最大公约数是%d\n", max);

	system("pause");
	return 0;
}

质因数分解法:
把每个数分别分解质因数,再把各数中的全部公有质因数提取出来连乘,所得的积就是这几个数的最大公约数。

例如:求24和60的最大公约数,先分解质因数,得24=2×2×2×3,60=2×2×3×5,24与60的全部公有的质因数是2、2、3,它们的积是2×2×3=12,所以,(24,60)=12。
把几个数先分别分解质因数,再把各数中的全部公有的质因数和独有的质因数提取出来连乘,所得的积就是这几个数的最小公倍数。

但是质因数分解法有一个最大的缺陷:分解质因数只针对合数。
所以此博客不讨论!因为用户输入的时候不一定清楚输入的数是不是合数!

短除法:
短除法求最大公约数,先用这几个数的公约数连续去除,一直除到所有的商互质为止,然后把所有的除数连乘起来,所得的积就是这几个数的最大公约数。

短除法的本质就是质因数分解法。所以此博客不讨论!

解法二:辗转相除法
辗转相除法是求两个自然数的最大公约数的一种方法,也叫欧几里德算法。
例如:求(319,377):
∵ 319÷377=0(余319)
∴(319,377)=(377,319);
∵ 377÷319=1(余58)
∴(377,319)=(319,58);
∵ 319÷58=5(余29)
∴ (319,58)=(58,29);
∵ 58÷29=2(余0)
∴ (58,29)= 29;
∴ (319,377)=29。

用辗转相除法求几个数的最大公约数,可以先求出其中任意两个数的最大公约数,再求这个最大公约数与第三个数的最大公约数,依次求下去,直到最后一个数为止。最后所得的那个最大公约数,就是所有这些数的最大公约数。

程序代码:

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int a, b, c;

	printf("请输入两个数:");
	scanf("%d%d", &a, &b);
	while ( c=a % b )
	{
		a = b;
		b = c;
	}
	printf("最大公约数是%d\n", b);
	system("pause");

	return 0;
}

代码生成图:
在这里插入图片描述

解法三:更相减损法
更相减损法:也叫更相减损术,是出自《九章算术》的一种求最大公约数的算法,它原本是为约分而设计的,但它适用于任何需要求最大公约数的场合。
《九章算术》是中国古代的数学专著,其中的“更相减损术”可以用来求两个数的最大公约数,即“可半者半之,不可半者,副置分母、子之数,以少减多,更相减损,求其等也。以等数约之。”
翻译成现代语言如下:
第一步:任意给定两个正整数;判断它们是否都是偶数。若是,则用2约简;若不是则执行第二步。
第二步:以较大的数减较小的数,接着把所得的差与较小的数比较,并以大数减小数。继续这个操作,直到所得的减数和差相等为止。
则第一步中约掉的若干个2与第二步中等数的乘积就是所求的最大公约数。
其中所说的“等数”,就是最大公约数。求“等数”的办法是“更相减损”法。所以更相减损法也叫等值算法。

程序代码:

#include<stdio.h>
#include<stdlib.h>

int main(){
	int a, b;
	int count = 1;

	printf("请输入两个数:");
	scanf("%d%d", &a, &b);

	while (a % 2 == 0 && b % 2 == 0) {
		a /= 2;
		b /= 2;
		count *= 2;
	}

	while (a != b)
	{
		if (a > b)
			a -= b;
		else
			b -= a;
	}

	printf("最大公约数是%d\n", b*count);

	system("pause");
	return 0;
}