辗转相除法(欧几里得算法)深度解析
辗转相除法-欧几里得算法深度解析
- 前言
- 一、辗转相除法的数学原理
- 1.1 最大公约数(GCD)
- 1.2 核心数学定理:带余除法
- 1.3 算法核心步骤
- 二、算法实现:递归与迭代
- 2.1 cpp递归实现
- 2.2 Python迭代实现
- 2.3 处理负数与 0 的边界情况
- 三、复杂度分析:对数级效率
- 3.1 时间复杂度
- 3.2 空间复杂度
- 四、扩展:从辗转相除法到扩展欧几里得算法
- 4.1 扩展欧几里得算法
- 4.2 应用场景
- 五、与其他 GCD 算法的对比
- 5.1 更相减损术(九章算术算法)
- 5.2 二进制 GCD 算法
- 六、数学&工程应用场景
- 6.1 分数约分
- 6.2 多项式 GCD
- 6.3 计算机底层实现
- 总结
前言
辗转相除法(Euclidean Algorithm)是求解两个正整数最大公约数(GCD, Greatest Common Divisor)的经典算法。它以简洁的数学原理和高效的计算过程,成为数论算法的基石之一,广泛应用于密码学、代数运算、计算机科学等领域。本文我将从数学原理、算法实现、复杂度分析、应用场景等多个维度,深入解析这一经典算法,结合代码示例与数学证明,带你全面掌握辗转相除法的核心思想。
一、辗转相除法的数学原理
1.1 最大公约数(GCD)
两个正整数 a a a 和 b b b 的最大公约数 d d d,是同时整除 a a a 和 b b b 的最大正整数,记作 d = gcd ( a , b ) d = \gcd(a, b) d=gcd(a,b)。例如:
- gcd ( 24 , 18 ) = 6 \gcd(24, 18) = 6 gcd(24,18)=6
- gcd ( 45 , 15 ) = 15 \gcd(45, 15) = 15 gcd(45,15)=15
1.2 核心数学定理:带余除法
辗转相除法基于数论中的带余除法:对于任意两个正整数 a a a 和 b b b( a > b a > b a>b),存在唯一的整数 q q q(商)和 r r r(余数),使得:
a = b ⋅ q + r ( 0 ≤ r < b ) a = b \cdot q + r \quad (0 \leq r < b) a=b⋅q+r(0≤r<b)
此时, gcd ( a , b ) = gcd ( b , r ) \gcd(a, b) = \gcd(b, r) gcd(a,b)=gcd(b,r)。证明:设 d d d 是 a a a 和 b b b 的公约数,则 d d d 整除 a − b ⋅ q = r a - b \cdot q = r a−b⋅q=r,因此 d d d 也是 b b b 和 r r r 的公约数。反之,若 d d d 是 b b b 和 r r r 的公约数,则 d d d 整除 b ⋅ q + r = a b \cdot q + r = a b⋅q+r=a,因此 d d d 也是 a a a 和 b b b 的公约数。故两者的公约数集合相同,最大公约数必然相等。
1.3 算法核心步骤
辗转相除法通过不断应用带余除法,将原问题转化为更小规模的子问题,直到余数为 0 时停止:
- 用较大数除以较小数,得到余数 r r r。
- 若 r = 0 r = 0 r=0,则较小数即为最大公约数。
- 否则,将较小数作为新的较大数,余数作为新的较小数,重复步骤 1。
示例:计算
- 252 A ~ ⋅ 105 = 2 252 ÷ 105 = 2 252A~⋅105=2 余 42 42 42 → gcd ( 252 , 105 ) = gcd ( 105 , 42 ) \gcd(252, 105) = \gcd(105, 42) gcd(252,105)=gcd(105,42)
- 105 A ~ ⋅ 42 = 2 105 ÷ 42 = 2 105A~⋅42=2 余 21 21 21 → gcd ( 105 , 42 ) = gcd ( 42 , 21 ) \gcd(105, 42) = \gcd(42, 21) gcd(105,42)=gcd(42,21)
- 42 A ~ ⋅ 21 = 2 42 ÷ 21 = 2 42A~⋅21=2 余 0 0 0 → gcd ( 42 , 21 ) = 21 \gcd(42, 21) = 21 gcd(42,21)=21最终结果为 21 21 21。
二、算法实现:递归与迭代
2.1 cpp递归实现
#include <iostream>
using namespace std;int gcd(int a, int b) {if (b == 0) return a;return gcd(b, a % b);
}int main() {cout << gcd(252, 105) << endl; // 输出21return 0;
}
递归逻辑:
-
终止条件:当 b = 0 b = 0 b=0 时,返回 a a a(此时 a a a 是上一步的除数,即当前最大公约数)。
-
递归调用:将问题转化为 gcd ( b , a % b ) \gcd(b, a \% b) gcd(b,a%b),其中 a % b a \% b a%b 是上一步的余数。
2.2 Python迭代实现
def gcd(a, b):while b != 0:a, b = b, a % breturn aprint(gcd(252, 105)) # 输出21
迭代逻辑:
- 用循环替代递归,通过不断更新 a a a 和 b b b 的值( a a a 变为原 b b b, b b b 变为原 a % b a \% b a%b),直到 b = 0 b = 0 b=0 时返回 a a a。
2.3 处理负数与 0 的边界情况
实际应用中需处理非正整数输入:
def gcd(a, b):a = abs(a)b = abs(b)while b != 0:a, b = b, a % breturn a
-
先取绝对值,确保输入为正整数。
-
若输入包含 0(如 gcd ( 0 , 5 ) = 5 \gcd(0, 5) = 5 gcd(0,5)=5),算法依然成立,因为 gcd ( 0 , n ) = n \gcd(0, n) = n gcd(0,n)=n( n > 0 n > 0 n>0)。
三、复杂度分析:对数级效率
3.1 时间复杂度
辗转相除法的时间复杂度为 O ( log min ( a , b ) ) O(\log \min(a, b)) O(logmin(a,b)),证明基于以下两点:
-
余数递减性质:每次迭代后,余数 r = a % b r = a \% b r=a%b 满足 r < b r < b r<b,且当 a > b a > b a>b 时, a % b ≤ a / 2 a \% b \leq a/2 a%b≤a/2(当 a < 2 b a < 2b a<2b 时,余数 a − b < b a - b < b a−b<b;当 a ≥ 2 b a \geq 2b a≥2b 时,余数 a % b ≤ a / 2 a \% b \leq a/2 a%b≤a/2)。
-
斐波那契数列下界:算法的迭代次数不超过较小数的位数。设 a > b a > b a>b,迭代次数为 k k k,则 a ≥ F ( k + 2 ) a \geq F(k+2) a≥F(k+2), b ≥ F ( k + 1 ) b \geq F(k+1) b≥F(k+1),其中 F ( n ) F(n) F(n) 是斐波那契数列。由于斐波那契数列呈指数增长,迭代次数 k = O ( log b ) k = O(\log b) k=O(logb)。
3.2 空间复杂度
-
递归实现:空间复杂度为 O ( log b ) O(\log b) O(logb)(递归栈深度)。
-
迭代实现:空间复杂度为 O ( 1 ) O(1) O(1)(仅使用常数级变量)。
四、扩展:从辗转相除法到扩展欧几里得算法
4.1 扩展欧几里得算法
辗转相除法的扩展版本可求解贝祖等式 a x + b y = gcd ( a , b ) ax + by = \gcd(a, b) ax+by=gcd(a,b) 的整数解 ( x , y ) (x, y) (x,y)。算法思想:在求 gcd ( a , b ) \gcd(a, b) gcd(a,b) 的过程中,反向推导 x x x 和 y y y 的值。递归实现(Python):
def extended_gcd(a, b):if b == 0:return a, 1, 0gcd, x1, y1 = extended_gcd(b, a % b)x = y1y = x1 - (a // b) * y1return gcd, x, ygcd, x, y = extended_gcd(252, 105)
print(f"gcd={gcd}, x={x}, y={y}")
# 输出 gcd=21, x=-1, y=2(252*(-1) + 105*2 = 21)
4.2 应用场景
-
求解线性同余方程:如 a x ≡ c m o d m ax \equiv c \mod m ax≡cmodm,需先判断 gcd ( a , m ) \gcd(a, m) gcd(a,m) 是否整除 c c c。
-
密码学:RSA 算法中用于计算模逆元(若 a a a 和 m m m 互质,存在唯一的 x x x 使得 a x ≡ 1 m o d m ax \equiv 1 \mod m ax≡1modm)。
五、与其他 GCD 算法的对比
5.1 更相减损术(九章算术算法)
-
原理:通过反复做差代替取余: gcd ( a , b ) = gcd ( ∣ a − b ∣ , b ) \gcd(a, b) = \gcd(|a-b|, b) gcd(a,b)=gcd(∣a−b∣,b)( a > b a > b a>b)。
-
示例: gcd ( 252 , 105 ) = gcd ( 147 , 105 ) = gcd ( 42 , 105 ) = gcd ( 42 , 63 ) = gcd ( 42 , 21 ) = 21 \gcd(252, 105) = \gcd(147, 105) = \gcd(42, 105) = \gcd(42, 63) = \gcd(42, 21) = 21 gcd(252,105)=gcd(147,105)=gcd(42,105)=gcd(42,63)=gcd(42,21)=21。
-
优缺点:避免取余运算(适合大数),但最坏情况时间复杂度为 O ( a + b ) O(a + b) O(a+b)(如 gcd ( n , 1 ) \gcd(n, 1) gcd(n,1) 需要 n − 1 n-1 n−1 次减法),效率低于辗转相除法。
5.2 二进制 GCD 算法
- 原理:结合移位运算和减法,适用于二进制系统:
-
若 a a a 和 b b b 均为偶数, gcd ( a , b ) = 2 ⋅ gcd ( a / 2 , b / 2 ) \gcd(a, b) = 2 \cdot \gcd(a/2, b/2) gcd(a,b)=2⋅gcd(a/2,b/2)。
-
若 a a a 为偶数、 b b b 为奇数, gcd ( a , b ) = gcd ( a / 2 , b ) \gcd(a, b) = \gcd(a/2, b) gcd(a,b)=gcd(a/2,b)。
-
若 a a a 和 b b b 均为奇数, gcd ( a , b ) = gcd ( ∣ a − b ∣ , b ) \gcd(a, b) = \gcd(|a-b|, b) gcd(a,b)=gcd(∣a−b∣,b)。
- 优点:避免大数取余,适合计算机底层实现(如 Python 的
math.gcd
内部优化)。
六、数学&工程应用场景
6.1 分数约分
将分数 a b \frac{a}{b} ba 约分为最简形式:
def reduce_fraction(a, b):g = gcd(a, b)return (a // g, b // g)print(reduce_fraction(18, 24)) # 输出 (3, 4)
6.2 多项式 GCD
在符号计算中,辗转相除法可扩展到多项式环,用于求解两个多项式的最大公因式,步骤与整数 GCD 类似,将取余运算替换为多项式除法。
6.3 计算机底层实现
-
编程语言内置函数:Python 的
math.gcd
、C++ 的<algorithm>
库中的__gcd
均基于优化的辗转相除法。 -
加密算法:RSA 算法中,通过扩展欧几里得算法计算私钥,确保加密和解密的正确性。
总结
辗转相除法以简洁的数学原理和高效的计算过程,成为数论算法的典范。它不仅解决了最大公约数的求解问题,还衍生出扩展算法,在密码学、代数运算等领域发挥关键作用。理解辗转相除法,不仅是掌握一个算法,更是理解 “问题简化” 和 “数学归纳” 思想的重要实践。
That’s all, thanks for reading!
觉得有用就点个赞
、收进收藏夹
吧!关注
我,获取更多干货~