最大公约数(The Great Common Divisor)
自己为了苦练内功,打算从高德纳的计算机程序设计艺术下手....目前刚看到了第一章的第二小节,感觉这本书还可以,可能自己还没有怎么深入理解吧.目前学下了一个基本的最大公约数的算法.记录如下:
最大公约数(The Great Common Divisor)是指两个整数m和n都能够整除的最大相同因子.目前常用的算法是欧几里得算法,又称辗转相除法. 算法的基本思想是假设r是m/n的余数,那么m可以表示为:
m = a*n + r (1)
假设m和n的最大公约数是d,因此当求m和n的最大公约数时,其实是在求 a*n + r和 n的最大公约数,即是在求n和r的最大公约数.递归下去,就得到了下面的算法描述.
算法E(欧几里得算法):给定两个正整数m和n,求他们的最大公因子.
E0: [确保m>=n] 如果m<n, 交换m和n
E1: [求余数]: 以n除m, 并令r为所得余数.
E2: [余数为0?] 若r=0, 算法结束,此时的n就是答案.否则,转到E3
E3:[减少]: 置m<-n, n<-r, 并返回E1(这就是辗转相除法的核心)
相应的C语言实现代码在附录.
最小公倍数(The Least Common Multiple)
看完书上的介绍,想起了与最大公约数相对应的是最小公倍数(The Least Common Multiple), 自己查了些现成的资料.发现了一个求最小公倍数的好的算法:
算法的基本思想是利用m和n的最大公约数来求m和n的最小公倍数.假设m和n的最小公倍数为lcm(m,n), 最大公约数为gcd(m,n)则:
lcm(m,n) = m*n /gcd(m,n) (2)
解释如下:我们知道lcm(m,n) <= m*n,而且lcm(m,n)必然能够被m*n整除,即lcm(m,n) = (m*n)/x . 为了使lcm(m,n)最小,就要使x尽可能的最大.为了求x的最大值, (m*n)/x可以表示为 (m/x) * n 和(n/x) * m 我们知道lcm(m,n)肯定是整数, 那么m/x 和n/x 也必须是整数, 因此为了使x最大从而lcm(m,n)最小, 就要找到使m/x和n/x同时为整数的最大的x值,这个值正好是gcd(m,n). 因此就解释了式(2)的正确性.
附录A: 最大公约数C语言描述:
int r_gcd(int m, int n)
{
int rem = 0;
if( m < n )
{
r_swap(&m, &n);
}
for( ; ; )
{
rem = m%n;
if(!rem)
{
break;
}
m = n;
n = rem;
}
return n;
}