欧几里得算法、证明及扩展,看这一篇就够了

数学的力量是伟大的,也是美丽的。 —— 本人说的

本文算是对中佛罗里达大学提供的对欧几里得算法证明的翻译,想看英文证明的, 这里是链接>英文材料<

欧几里得算法 (Euclid’s Algorithm)

众所周知,大名鼎鼎的欧几里得是为了求两个整数之间的最大公因数,也就是所谓的辗转相除法了,在下面的内容中,我将分别从欧几里得算法证明、欧几里得算法扩展和代码实现来介绍。先作一个约定,若一个数p可以被q整除,也就是说q除以p余数为0,我们记 p | q

最大公因数

我们记gcd(a,b)为a和b之间的最大公因数,gcd denotesgreatest common divisor,如果一个整数c是a和b的最大公因数,那么必然满足以下两条规格:

  1. c | a 且c | b
  2. 对于任何a和b的公共因数d,d | c

实际上,规则2保证了规则1中的c就是a和b的最大公因数

形式化描述

欧几里得算法的形式化描述如下,其中所有的字母都代表整数:
a = q 1 b + r 1 , 其 中 0 < r 1 < b a = q_1b + r_1, 其中 0 < r_1< b a=q1b+r1,0<r1<b

b = q 2 r 1 + r 2 , 其 中 0 < r 2 < r 1 b = q_2r_1 + r_2, 其中 0 < r_2< r_1 b=q2r1+r2,0<r2<r1

r 1 = q 3 r 2 + r 3 , 其 中 0 < r 3 < r 2 r_1 = q_3r_2 + r_3, 其中 0 < r_3 < r_2 r1=q3r2+r3,0<r3<r2

. . . ... ...

r i = q i + 2 r i + 1 + r i + 2 , 其 中 0 < r i + 2 < r i + 1 r_i = q_{i+2}r_{i+1} + r_{i+2}, 其中 0 < r_{i+2} < r_{i+1} ri=qi+2ri+1+ri+2,0<ri+2<ri+1

. . . ... ...

r k − 1 = q k + 1 r k r_{k-1}=q_{k+1}r_k rk1=qk+1rk

g c d ( a , b ) = r k gcd(a,b)=r_k gcd(a,b)=rk

也就是说, gcd(a,b)= gcd(b,a%b),一直递归处理到a%b,那时对应的被除数/除数就是最大公因数c了。

考虑以下这个例子,GCD(125, 87)
125 = 1*87 + 38
87	= 2*38 + 11
38	= 3*11 + 5
11  = 2*5  + 1
5	= 5*1

所以,GCD(125, 87)=1

证明

证明gcd返回的是a和b之间的最大公因数,我们可以分两步来证明:

  • 1.首先,我们证明,gcd返回的数确实是a和b之间的公因数

回顾一下上面的公式:
a = q 1 b + r 1 , 其 中 0 < r 1 < b a = q_1b + r_1, 其中 0 < r_1< b a=q1b+r1,0<r1<b

b = q 2 r 1 + r 2 , 其 中 0 < r 2 < r 1 b = q_2r_1 + r_2, 其中 0 < r_2< r_1 b=q2r1+r2,0<r2<r1

r 1 = q 3 r 2 + r 3 , 其 中 0 < r 3 < r 2 r_1 = q_3r_2 + r_3, 其中 0 < r_3 < r_2 r1=q3r2+r3,0<r3<r2

. . . ... ...

r i = q i + 2 r i + 1 + r i + 2 , 其 中 0 < r i + 2 < r i + 1 r_i = q_{i+2}r_{i+1} + r_{i+2}, 其中 0 < r_{i+2} < r_{i+1} ri=qi+2ri+1+ri+2,0<ri+2<ri+1

. . . ... ...

r k − 1 = q k + 1 r k r_{k-1}=q_{k+1}r_k rk1=qk+1rk

从最后一个式子,我们知道 r k ∣ r k − 1 r_{k} | r_{k-1} rkrk1,然后再考虑它的上一个式子 r k − 2 = q k r k − 1 + r k = q k q k + 1 r k + r k = ( q k q k + 1 + 1 ) r k r_{k-2}=q_{k}r_{k-1}+r_{k}=q_{k}q_{k+1}r_k+r_{k}=(q_{k}q_{k+1}+1)r_{k} rk2=qkrk1+rk=qkqk+1rk+rk=(qkqk+1+1)rk, 也就是说 r k ∣ r k − 2 r_{k} | r_{k-2} rkrk2,按照同样的方法往上面的式子一直求下去,直到最顶端的a和b,可以得到 r k ∣ a r_{k} | a rka r k ∣ b r_{k} | b rkb, 这里我就不再多说了,自己可以在纸上稍微演算一下。

OK,我们的目标达到,得证:gcd返回的数确实是a和b之间的公因数。

  • 2.其次,我们要证明,对于任何a和b的公共因数d,d | gcd(a,b), 也就是说给定任何一个a和b的公因数d,它总是能被gcd(a,b)整除

这里,我们假设任意的a和吧之间的公因数为d,既然是公因数,那么必然有 a = d a ′ , b = d b ′ a=da',b=db' a=da,b=db, 再次回顾一下公式:
a = q 1 b + r 1 , 其 中 0 < r 1 < b a = q_1b + r_1, 其中 0 < r_1< b a=q1b+r1,0<r1<b

b = q 2 r 1 + r 2 , 其 中 0 < r 2 < r 1 b = q_2r_1 + r_2, 其中 0 < r_2< r_1 b=q2r1+r2,0<r2<r1

r 1 = q 3 r 2 + r 3 , 其 中 0 < r 3 < r 2 r_1 = q_3r_2 + r_3, 其中 0 < r_3 < r_2 r1=q3r2+r3,0<r3<r2

. . . ... ...

r i = q i + 2 r i + 1 + r i + 2 , 其 中 0 < r i + 2 < r i + 1 r_i = q_{i+2}r_{i+1} + r_{i+2}, 其中 0 < r_{i+2} < r_{i+1} ri=qi+2ri+1+ri+2,0<ri+2<ri+1

. . . ... ...

r k − 1 = q k + 1 r k r_{k-1}=q_{k+1}r_k rk1=qk+1rk
这次,我们从第一个式子开始, a = q 1 b + r 1 a = q_1b + r_1 a=q1b+r1,即 r 1 = a − q 1 b = d a ′ − q 1 d b ′ = d ( a ′ − q 1 b ′ ) r_1=a-q_1b=da'-q_1db'=d(a'-q_1b') r1=aq1b=daq1db=d(aq1b) ,即 d ∣ r 1 d | r_1 dr1
继续看第二个式子, b = q 2 r 1 + r 2 b = q_2r_1 + r_2 b=q2r1+r2,有了上面的 d ∣ r 1 d | r_1 dr1后,我们记 r 1 = d r 1 ′ r_1= dr_1' r1=dr1,于是 b = q 2 r 1 + r 2 = q 2 d r 1 ′ + r 2 b = q_2r_1 + r_2=q_2dr_1'+r_2 b=q2r1+r2=q2dr1+r2, 即 r 2 = b − q 2 d r 1 ′ = d b ′ − q 2 d r 1 ′ = d ( b ′ − q 2 r 1 ′ ) r_2=b-q_2dr_1'=db'-q_2dr_1'=d(b'-q_2r_1') r2=bq2dr1=dbq2dr1=d(bq2r1),也就是说 d ∣ r 2 d | r_2 dr2
按照这样的方式一直计算下去,直到最后一个式子,可以证明 d ∣ r k d | r_k drk

至此,rule1和rule2证毕,欧几里得算法得证。

欧几里得算法扩展

若整数a和b的最大公因数为d,即gcd(a,b)=d,那么一定存在整数x、y使得下式成立:
a x + b y = g c d ( a , b ) . ax + by = gcd(a,b). ax+by=gcd(a,b).

让我们再次回归公式,三顾欧几里得算法了。。。
a = q 1 b + r 1 , 其 中 0 < r 1 < b a = q_1b + r_1, 其中 0 < r_1< b a=q1b+r1,0<r1<b

b = q 2 r 1 + r 2 , 其 中 0 < r 2 < r 1 b = q_2r_1 + r_2, 其中 0 < r_2< r_1 b=q2r1+r2,0<r2<r1

r 1 = q 3 r 2 + r 3 , 其 中 0 < r 3 < r 2 r_1 = q_3r_2 + r_3, 其中 0 < r_3 < r_2 r1=q3r2+r3,0<r3<r2

. . . ... ...

r i = q i + 2 r i + 1 + r i + 2 , 其 中 0 < r i + 2 < r i + 1 r_i = q_{i+2}r_{i+1} + r_{i+2}, 其中 0 < r_{i+2} < r_{i+1} ri=qi+2ri+1+ri+2,0<ri+2<ri+1

. . . ... ...

r k − 2 = q k r k − 1 + r k , 其 中 0 < r k < r k − 1 r_{k-2} = q_kr_{k-1}+ r_k, 其中 0 < r_k < r_{k-1} rk2=qkrk1+rk,0<rk<rk1

r k − 1 = q k + 1 r k r_{k-1}=q_{k+1}r_k rk1=qk+1rk

从倒数第二个式子看起, g c d ( a , b ) = r k = r k − 2 − q k r k − 1 gcd(a,b)=r_k=r_{k-2}-q_kr_{k-1} gcd(a,b)=rk=rk2qkrk1,再看倒数第三个式子 r k − 1 = r k − 3 − q k − 1 r k − 2 r_{k-1}=r_{k-3}-q_{k-1}r_{k-2} rk1=rk3qk1rk2,将后面这个式子代入前者,得到

g c d ( a , b ) = r k = r k − 2 − q k ( r k − 3 − q k − 1 r k − 2 ) = ( 1 + q k q k − 1 ) r k − 2 − q k r k − 3 gcd(a,b)=r_k=r_{k-2}-q_k(r_{k-3}-q_{k-1}r_{k-2})=(1+q_kq_{k-1})r_{k-2}-q_kr_{k-3} gcd(a,b)=rk=rk2qk(rk3qk1rk2)=(1+qkqk1)rk2qkrk3

也就是说,gcd(a,b)是 r k − 2 r_{k-2} rk2 r k − 3 r_{k-3} rk3的线性组合,按照类似的方法,你可以继续将 r k − 2 r_{k-2} rk2替换掉然后再代入,可以得到gcd(a,b)是 r k − 3 r_{k-3} rk3 r k − 4 r_{k-4} rk4的线性组合,再替换掉 r k − 3 r_{k-3} rk3并代入,可以得到gcd(a,b)是 r k − 4 r_{k-4} rk4 r k − 5 r_{k-5} rk5的线性组合。。。然后一直这样下去,你就可以得到gcd(a,b)是a和b的线性组合,证毕。

代码

至于代码,那就很简答了,辗转相除,是我们从学c语言开始就会背的程序了,23333…

int get_gcd(int a,int b)   // 假设a>=b
{
	int r=a%b;
	while(r!=0)
	{
		a=b;
		b=r;
		r=a%b
	}
	return b;
}

你可能感兴趣的:(算法设计与分析)