辗转相除法(欧几里得算法)深度解析

#新星杯·14天创作挑战营·第11期#

前言

辗转相除法(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=bq+r(0r<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 abq=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 bq+r=a,因此 d d d 也是 a a a b b b 的公约数。故两者的公约数集合相同,最大公约数必然相等。

1.3 算法核心步骤

辗转相除法通过不断应用带余除法,将原问题转化为更小规模的子问题,直到余数为 0 时停止:

  1. 用较大数除以较小数,得到余数 r r r
  2. r = 0 r = 0 r=0,则较小数即为最大公约数。
  3. 否则,将较小数作为新的较大数,余数作为新的较小数,重复步骤 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; // 输出21
    return 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 % b
    return a

print(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 % b
    return 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)),证明基于以下两点:

  1. 余数递减性质:每次迭代后,余数 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%ba/2(当 a < 2 b a < 2b a<2b 时,余数 a − b < b a - b < b ab<b;当 a ≥ 2 b a \geq 2b a2b 时,余数 a % b ≤ a / 2 a \% b \leq a/2 a%ba/2)。

  2. 斐波那契数列下界:算法的迭代次数不超过较小数的位数。设 a > b a > b a>b,迭代次数为 k k k,则 a ≥ F ( k + 2 ) a \geq F(k+2) aF(k+2) b ≥ F ( k + 1 ) b \geq F(k+1) bF(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, 0
    gcd, x1, y1 = extended_gcd(b, a % b)
    x = y1
    y = x1 - (a // b) * y1
    return gcd, x, y

gcd, 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 axcmodm,需先判断 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 ax1modm)。

五、与其他 GCD 算法的对比

5.1 更相减损术(九章算术算法)

  • 原理:通过反复做差代替取余: gcd ⁡ ( a , b ) = gcd ⁡ ( ∣ a − b ∣ , b ) \gcd(a, b) = \gcd(|a-b|, b) gcd(a,b)=gcd(ab,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 n1 次减法),效率低于辗转相除法。

5.2 二进制 GCD 算法

  • 原理:结合移位运算和减法,适用于二进制系统:
  1. 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)=2gcd(a/2,b/2)

  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)

  3. a a a b b b 均为奇数, gcd ⁡ ( a , b ) = gcd ⁡ ( ∣ a − b ∣ , b ) \gcd(a, b) = \gcd(|a-b|, b) gcd(a,b)=gcd(ab,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!
觉得有用就点个赞、收进收藏夹吧!关注我,获取更多干货~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值