Euclid算法(即欧几里得算法)是求两个正整数的最大公因子的算法。
我们用gcd(a, b)表示a和b的最大公因子。则
gcd(a, b) = max[k, 其中k | a 且k | b]
因为我们所求的最大公因子是正数,所以gcd(a, b) = gcd(a, -b) = gcd(-a, b) = gcd(-a,-b)。一般来说,gcd(a, b) = gcd(|a|, |b|)。
Euclid算法基于以下的定理:
对于任意非负整数a和任意正整数b,有:
gcd(a,b) = gcd(b,a mod b) (a>b 且a mod b 不为0) (1)
定理证明:
假设d = gcd(a, b),根据gcd的定义,则有d|a, d|b成立。对于任意正整数a, b可以表示成如下形式:
a = kb + r≡ r mod b
amod b = r 其中k,r为整数。
因此,对某个整数k,有(a mod b) = a – kb。
因为 d|b, d|kb,且d|a,所以有d|(a mod b),这说明d是b和(a mod b)的公因子。反之,如果d是b和(a mod b)的公因子,那么d|kb,并且由此可知d|[kb + (a mod b)],即d|a,因此a和b公因子的集合与b和(a mod b)公因子的集合相等。因此,两对数的gcd相同,定理得证。
Euclid算法通过重复使用公式(1)来求最大公因子。算法中假设a > b > 0。因为gcd(a, b) = gcd(|a|, |b|),所以仅考虑正整数的情况即可。
算法过程如下:
1、A←a, B←b
2、若B = 0,则返回A=gcd(a, b)
3、R = A modB
4、A←B
5、B←R
6、转到2
以下Java实现Euclid算法的非递归版和递归版代码:
public class Euclid {
public static void main(String[] args) {
System.out.println("No recursive gcd = " + gcd(1970, 1066));
gcdR(1970, 1066);
System.out.println("Recursive gcd = " + gcdR(1970, 1066));
}
// 非递归版
private static int gcd(int a, int b){
if(b == 0){
return a;
}
int r;
while(b != 0){
r = a % b;
a = b;
b = r;
}
return a;
}
// 递归版
private static int gcdR(int a, int b){
if(b == 0){
return a;
}
return gcdR(b, a % b);
}
}