C 练习实例16 – 最大公约数和最小公倍数(手把手讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
在编程学习的旅程中,数学问题始终是一个重要且有趣的领域。本文将围绕 “C 练习实例16 – 最大公约数和最小公倍数” 展开,通过深入浅出的讲解,帮助读者理解这两个基础概念,并掌握其实现方法。无论是编程初学者还是希望巩固算法基础的开发者,都能通过本文获得实用的技巧和启发。
一、数学基础:最大公约数(GCD)与最小公倍数(LCM)
1.1 最大公约数(GCD)的定义
最大公约数(Greatest Common Divisor,简称 GCD)是指两个或多个整数共有约数中最大的一个。例如,数字 8 和 12 的公约数包括 1、2、4,其中最大的是 4,因此它们的 GCD 是 4。
形象比喻:可以想象两个人分糖果,如果两人分到的糖果数量必须相等且没有剩余,那么最大公约数就是两人能分到的“最大相同数量”。
1.2 最小公倍数(LCM)的定义
最小公倍数(Least Common Multiple,简称 LCM)是指两个或多个整数公有的倍数中最小的一个。例如,数字 3 和 5 的公倍数有 15、30、45 等,其中最小的是 15,因此它们的 LCM 是 15。
形象比喻:假设两个人以不同步速走路,最小公倍数就是他们再次同时到达起点所需的最短时间。
1.3 数学关系:GCD 与 LCM 的联系
GCD 和 LCM 之间存在一个核心公式:
[
\text{LCM}(a, b) = \frac{a \times b}{\text{GCD}(a, b)}
]
这个公式表明,只要求出 GCD,就能轻松计算 LCM。因此,实现 GCD 的算法是解决问题的关键。
二、算法实现:如何计算 GCD?
2.1 穷举法(Brute Force)
穷举法是最直观但效率最低的方法。其核心思想是遍历从 1 到较小数的所有整数,找到能同时整除两个数的最大值。
#include <stdio.h>
int gcd_brute_force(int a, int b) {
int min = (a < b) ? a : b;
for (int i = min; i >= 1; i--) {
if (a % i == 0 && b % i == 0) {
return i;
}
}
return 1; // 最小公约数为 1
}
int main() {
int a = 8, b = 12;
printf("GCD of %d and %d is %d\n", a, b, gcd_brute_force(a, b));
return 0;
}
优缺点分析:
| 特点 | 优点 | 缺点 |
|---------------------|-----------------------------|-----------------------------|
| 时间复杂度 | O(n),n 为较小数的值 | 对大数效率极低 |
| 适用场景 | 小规模数据或教学演示 | 不适合实际开发或大规模计算 |
2.2 欧几里得算法(Euclidean Algorithm)
欧几里得算法是计算 GCD 的经典方法,其核心公式为:
[
\text{GCD}(a, b) = \text{GCD}(b, a % b) \quad \text{(当 } b \neq 0 \text{ 时)}
]
当 ( b = 0 ) 时,( a ) 即为 GCD。
2.2.1 迭代实现
int gcd_euclidean_iterative(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
2.2.2 递归实现
int gcd_euclidean_recursive(int a, int b) {
if (b == 0) {
return a;
}
return gcd_euclidean_recursive(b, a % b);
}
效率对比:
欧几里得算法的时间复杂度为 O(log(min(a, b))),远优于穷举法。例如,计算 ( \text{GCD}(1000000, 999999) ) 时,穷举法需要遍历 100 万次,而欧几里得算法仅需约 10 次迭代。
三、代码示例与完整实现
3.1 完整程序:C 练习实例16 的标准实现
#include <stdio.h>
// 欧几里得算法(递归实现)
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
// 计算 LCM 的函数
int lcm(int a, int b) {
return (a * b) / gcd(a, b);
}
int main() {
int num1, num2;
printf("Enter two integers: ");
scanf("%d %d", &num1, &num2);
int result_gcd = gcd(num1, num2);
int result_lcm = lcm(num1, num2);
printf("GCD of %d and %d is: %d\n", num1, num2, result_gcd);
printf("LCM of %d and %d is: %d\n", num1, num2, result_lcm);
return 0;
}
3.2 输入输出示例
Enter two integers: 24 36
GCD of 24 and 36 is: 12
LCM of 24 and 36 is: 72
四、进阶优化:Stein 算法(Binary GCD)
欧几里得算法虽然高效,但在某些场景下仍可优化。Stein 算法(也称二进制 GCD)通过二进制运算进一步提升效率,尤其适合处理大整数。
4.1 核心思想
- 性质 1:若 ( a ) 和 ( b ) 均为偶数,则 ( \text{GCD}(a, b) = 2 \times \text{GCD}(a/2, b/2) )。
- 性质 2:若 ( a ) 为偶数,( b ) 为奇数,则 ( \text{GCD}(a, b) = \text{GCD}(a/2, b) )。
- 性质 3:若 ( a ) 和 ( b ) 均为奇数,则 ( \text{GCD}(a, b) = \text{GCD}(b, a - b) )。
4.2 代码实现
int gcd_stein(int a, int b) {
if (a == 0) return b;
if (b == 0) return a;
if (a % 2 == 0 && b % 2 == 0) {
return 2 * gcd_stein(a / 2, b / 2);
} else if (a % 2 == 0) {
return gcd_stein(a / 2, b);
} else if (b % 2 == 0) {
return gcd_stein(a, b / 2);
} else {
return gcd_stein(b, a < b ? b - a : a - b);
}
}
效率对比:
对于二进制数,Stein 算法的效率比欧几里得算法更高,尤其是在硬件支持位运算的场景下(如嵌入式系统)。
五、实际案例与应用
5.1 简化分数
假设有一个分数 ( \frac{48}{60} ),通过计算 GCD(即 12),可将其简化为 ( \frac{4}{5} )。
5.2 时间同步问题
假设两个事件分别每 6 分钟和 9 分钟发生一次,它们的 LCM(即 18 分钟)就是两者同时发生的最短时间间隔。
六、常见问题与调试技巧
6.1 问题:负数输入如何处理?
- 解决方案:将输入的负数转换为正数再计算,因为 GCD 和 LCM 均为正数。
int a = -24, b = -36;
printf("GCD: %d", gcd(abs(a), abs(b)));
6.2 问题:当输入为 0 时如何处理?
- 解决方案:若其中一个数为 0,则 GCD 为另一个数的绝对值。例如,( \text{GCD}(0, 5) = 5 )。
七、结论
通过本文的讲解,我们系统学习了 “C 练习实例16 – 最大公约数和最小公倍数” 的实现方法,包括算法原理、代码示例和优化技巧。无论是编程初学者通过穷举法理解基础概念,还是开发者通过欧几里得或 Stein 算法提升效率,都能在实际项目中灵活应用这些知识。
未来,当遇到需要处理整数关系的问题时(如分数运算、时间同步、密码学等场景),掌握 GCD 和 LCM 的计算方法将成为解决问题的有力工具。
希望本文能为你的编程学习之路提供一份清晰的指南!