最大公约数(gcd):Euclid算法证明

来源:互联网 发布:单片机简易电子琴7键 编辑:程序博客网 时间:2024/06/06 16:45

转载:http://www.cnblogs.com/ider/archive/2010/11/16/gcd_euclid.html

在刚进大学学习C语言的时候,用的是谭浩强的那本“经典”教程(之所以加引号是在接触了更多的书籍和经过了高手的指点后,发现它算不上绝对的经典,但是是入门很好的书)。记得好像是在函数那一章的课后习题的第一题让写一个求两个数最大公约数的方法。因为当时是第一次接触C语言不知道这一个经典的题目,所以就直接翻阅答案去了。答案给出的提示就是用欧几里得的“辗转相除法”。当时把那个方法记了下来,只觉得太神奇了,会使用它但是一直没有理解,也不会证明它。

 

今年开始读研究生,选了Algorithm,相对于本科学习算法,在研究生阶段感觉很多是在复习这些内容,但也有更多的深入证明和学习。就拿gcd(Greatest Common Divisor)来说,在第0章就讲解了很多"模数"的知识和应用,在第三节课就证明了gcd的正确性。

 

因为gcd算法是一个经典的算法,所以在网上已经有很多关于它的证明方法和各种版本的实现方法。在此重述这些内容,只想巩固和积累一下自己所学到的知识,并方便将来的回顾。因为发现很多学过的内容在许久之后就会忘记,然后就要花很长的时间去找答案(比如大一的时候用得很熟练的求极限的各种公式,现在都想不太起来了,以致在解决问题的时候总是在怀疑做得是否正确)。

1个常识:

如果 a≥b 并且 b≤a,那么 a=b.

 

2个前提:

1)只在非负整数范围内讨论两个数 m 和 n 的最大公约数,即 m, n ∈ N.

2)0可以被任何数整除,但是0不能整除任何数,即 ∀x(x|0) and ∀x(0| x).


 

1个引理:

假设 k|a, k|b,则对任意的 x,y  ∈ Z, k|(xa+yb)均成立.

证明:

  k|a => a=pk, k|b => b==qk (其中 p,q ∈ Z)

  于是有 xa+yb=xpk+yqk=(xp+yq)k

  因为 k|(xp+yq)k, 所以 k|(xa+yb)


 

gcd的Euclid算法证明:

命题:对任意 m, n ∈ N,证明gcd(m,n) = gcd(n, m mod n)

证明:

  令 k=gcd(m,n),则 k|m 并且 k|n;

  令 j=gcd(n, m mod n), 则j|n 并且 j|(m mod n);

  对于m, 可以用n 表示为 m=pn+(m mod n);

  由引理可知 j|m(其中 x=p,y=1), 又 j|n,于是 j 是 m 和 n 的公约数(但不一定是最大的);

  因为 k 是 m 和 n 的最大公约数,所以必有 k≥j;

  通过另一种表示形式:(m mod n)=m-pn,同理可得:

  k|(m mod n),又k|n,于是 k 是 (m mod n) 和 n 的公约数(也不一定是最大的);

  同样由 j 是 n 和 (m mod n) 的最大公约数可以得到 j≥k;

  由常识,得出结论 k=j,

  即gcd(m,n) = gcd(n, m mod n) ,得证

 

gcd算法的C语言实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//递归版本
int gcd(int m,int n)
{
    return n? gcd(n,m%n) : m;
}
 
//无递归版本
int gcd(int m,int n)
{
    while (n)
    {
        n = m^n;
        m = m^n;
        n = (m^n)%m;
    }
     
    return m;
}
 
//当m=0,n=0时, gcd(m,n)返回0, 我们可以视其为无穷大 (见评论)
0 0