文章摘要
最大公因数(Greatest Common Divisor, GCD)和最小公倍数(Least Common Multiple, LCM)是数学中两个重要的概念,广泛用于分数运算、简化数学表达以及其他数论研究领域。在编程中,我们经常需要编写算法来计算这两个值,对于编程新手来说,这是一个很好的练手项目。本文将从基础入门到进阶优化来对最大公因数和最小公倍数进行求解。
基础入门-暴力求解
这种方法应该是所有学过C语言基础语法的人都应该要会的求解最大公因数和最小公倍数的方法。
此处已经涉及函数的运用,如果不懂函数知识点的请先对函数进行预习,对于此题,新手们只需要知道函数怎么定义和使用即可。
当我们初次尝试求解最大公因数(GCD)和最小公倍数(LCM)时,很容易想到的是暴力法,也叫穷举法。
在这种方法中,我们会拿两个数的每一个整数作为候选的公因数,看是否可以同时被两个数整除。具体过程如下:首先,我们设定公因数的目标值为1(假设两个正整数a和b,有公因数1)。然后,我们将每一个位于1和输入数字之间的数都作为候选因数,看它是否是这两个数字的公因数。这个“是否”通过模数运算(使用C语言中的%
操作符)实现,判断a和b除以这个候选因数的余数是否为零。如果为零,就说明该候选因数是这两个数字的公因数,所以要更新公因数的目标值。在遍历所有候选因数后,目标值即为这两个数字的最大公因数。
然后在求最小公倍数时,我们基于一个简单事实:两个数的乘积等于最大公因数乘以最小公倍数(即a*b = GCD(a,b)LCM(a,b))。所以我们可以通过(ab)/GCD(a,b)来得到最小公倍数。
#include <stdio.h>
// 求两个数的最大公因数(最简单暴力的方法)
int gcd_basic(int a, int b) {
int gcd = 1;
for (int i = 2; i <= a && i <= b; i++) {
if (a % i == 0 && b % i == 0) {
gcd = i;
}
}
return gcd;
}
// 求两个数的最小公倍数利用了gcd(a, b) * lcm(a, b) = a * b的性质
int lcm_basic(int a, int b) {
return (a * b) / gcd_basic(a, b);
}
int main() {
int a = 48, b = 18;
printf("The GCD of %d and %d is %d.\n", a, b, gcd_basic(a, b));
printf("The LCM of %d and %d is %d.\n", a, b, lcm_basic(a, b));
return 0;
}
主函数部分我们分别给a,b变量赋值48,18用于测试结果,很明显结果正确,这边建议新手们自行实现一遍,然后多试试几个测试点以此检验结果正确。
进阶-欧几里得算法
当两数较大时,基础篇中的方法可能会让程序运行缓慢甚至卡住。一个更高效的解法是利用算数定理来找出最大公因数:欧几里得算法,又叫辗转相除法。
欧几里得算法的原理在于:两个整数的最大公因数等于较大的数除以较小的数的余数与较小的数的最大公因数。这看起来有些抽象,让我们通过程序来理解它。
#include <stdio.h>
// 求最大公因数(欧几里得算法)
int gcd_intermediate(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
// 求两个数的最小公倍数利用了gcd(a, b) * lcm(a, b) = a * b的性质
int lcm_intermediate(int a, int b) {
return (a / gcd_intermediate(a, b)) * b;
}
int main() {
int a = 48, b = 18;
printf("The GCD of %d and %d is %d.\n", a, b, gcd_intermediate(a, b));
printf("The LCM of %d and %d is %d.\n", a, b, lcm_intermediate(a, b));
return 0;
}
在C语言代码中,我们通过一个循环,以较大的数字a和较小的数b作为输入。在这个循环中,我们不断的用a除以b并取余数,并将这个余数设为b,原来的b则设为a,如此循环循环直到b等于零。当b为零时,a的值就是两个数的最大公因数。
求最小公倍数的原理与基础篇节一样,也是利用了“两个数的乘积等于最大公因数乘以最小公倍数”这一事实。这次,根据欧几里得算法,我们首先除以最大公因数,然后再乘以另一个数。这样在数值较大时也能避免溢出的问题。
欧几里得算法实现的优化
这里我们再使用上递归和三元操作符‘?’,来使得用欧几里得算法求解最大公因数的代码变得更加简洁。
此处为函数代码:
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
函数流程的解释:
1.使用该函数时,我们首先检查b
是否等于0。这一步是递归的终止条件。如果b
的值为0,那么函数返回a
的值,因为根据欧几里得算法原理,如果两个数中一个数为0,则最大公因数是另一个非0数。
2.如果b
不等于0,函数不会立即返回一个值,而是进行一个递归调用,将b
作为第一个参数,a % b
(a
除以b
的余数)作为第二个参数。这一步将问题简化为一个更小的问题,即查找b
和a % b
的最大公因数。
3.递归继续执行,每次调用都会生成一个更小的整数对(即新的b
和新的a % b
),直到b
变成0为止。这时,余下的a
(在那一步的递归调用中的a
)就是初始数对a
和b
的最大公因数。
4.最终,递归“展开”并返回结果。每个嵌套的递归调用都会将其计算出的最大公因数返回给上一级调用,直到最初的函数调用得到最终结果并返回。
希望这篇文章能够帮助你更好地理解如何使用C语言求解最大公因数和最小公倍数,提高你编程解决问题的能力。