当前位置: 首页 > article >正文

算法 001. 辗转相除法(欧几里得算法)求最大公约数

1. 学习内容:

辗转相除法(欧几里得算法)
参考(维基中文):https://zh.wikipedia.org/wiki/%E8%BC%BE%E8%BD%89%E7%9B%B8%E9%99%A4%E6%B3%95#%E6%9C%80%E5%A4%A7%E5%85%AC%E7%BA%A6%E6%95%B0

a. 使用场景:
  • 求最大公约数
    – 两个整数的最大公约数等于其中较小的数和两数相除余数的最大公约数。比如:
  1. 两个数 p = 110, q = 121。较小的数为 p = 110,两数相除余数:q / p = 121 / 110 = 1……11,即余数为 11。所以 p = 110,q = 121 的最大公约数就是较小的数 p = 110 和 p、q 相除的余数 11 的最大公约数。110 和 11 最大公约数为 11。
  1. 两个数 a = 99,b = 180。较小的数为 a = 99,两数相除余数:b / a = 180 / 99 = 1……81,即余数为 81。所以 a = 99, b = 180 的最大公约数就是较小的数 a = 99 和 两者余数 81(记为 c = 81)的最大公约数。现在 a = 99 和 b = 180 的最大公约数问题等价于 a = 99,c = 81 的最大公约数问题。
    a = 99,c = 81 的最大公约数,再使用一次上面的计算方法:取两者较小的数 c = 81,两者相除的余数:a / c = 99 / 81 = 1……18(余数记为 d,d = 18),那么 a = 99, b = 180 的最大公约数问题变成了 a = 99, c = 81 的最大公约数问题,又变成了 c = 81,d = 18 之间的最大公约数问题。之后再来一次同样的计算——d = 18,c、d 相除的余数为 81 / 18 = 4 …… 9,问题就变成了 18 和 9 的最大公约数问题。显然最大公约数为 9。
    即最初的问题 a = 99,b = 180 的最大公约数是 9。

2. 学习时间:

2020.10.20


学习产出:

1. 理论

辗转相除法(简称 gcd(p, q),p、q 是两个输入数据)是一种递归算法,每一步计算的输出值就是下一步计算时的输入值。设 k 表示步骤数(从 0 开始计数),算法的计算过程如下(记 k 表示第 k 步,r 表示余数 ):

  1. 给定两个正整数 pq

  2. 步骤:
    第 一 步 : g c d ( p 0 , q 0 ) → p 0 = n 0 ∗ q 0 + r 0 → r 0 = p 0 % q 0 第一步:gcd(p_{0},q_{0})→ p_{0}=n_{0}*q_{0}+r_{0}→r_{0} = p_{0} \% q_{0} gcd(p0,q0)p0=n0q0+r0r0=p0%q0
    第 二 步 : g c d ( q 0 , r 0 ) → q 0 = n 1 ∗ r 0 + r 1 → r 1 = q 0 % r 0 第二步:gcd(q_{0},r_{0})→ q_{0}=n_{1}*r_{0}+r_{1}→r_{1} = q_{0} \% r_{0} gcd(q0,r0)q0=n1r0+r1r1=q0%r0
    第 三 步 : g c d ( r 0 , r 1 ) → r 0 = n 2 ∗ r 1 + r 2 → r 2 = r 0 % r 1 第三步:gcd(r_{0},r_{1})→ r_{0}=n_{2}*r_{1}+r_{2}→r_{2} = r_{0} \% r_{1} gcd(r0,r1)r0=n2r1+r2r2=r0%r1
    第 四 步 : g c d ( r 1 , r 2 ) → p 0 = n 3 ∗ r 2 + r 3 → r 3 = r 1 % r 2 第四步:gcd(r_{1},r_{2})→ p_{0}=n_{3}*r_{2}+r_{3}→r_{3} = r_{1} \% r_{2} gcd(r1,r2)p0=n3r2+r3r3=r1%r2
    ⋮ \vdots
    直 到 余 数 r n 为 0 结 束 直到余数 r_{n} 为 0 结束 rn0

  3. 解释:

  • 如果有 p < q,算法的第一步实际上会把两个数字交换
  • 因为 p、q 的有穷性,又每一步的余数都在减小并且不为负数,所以总会存在 n 使得 第 n 步的余数 r 为 0 使算法终止。
  • 重点:第 n-1 步的余数就是 p、q 的最大公约数
2. 例子

计算 a = 1071 和 b = 462 的最大公约数的过程如下:

  1. 从 1071 中不断减去 462 直到小于 462(可以减 2 次,即商 n0 = 2),余数是 147:
    1071 = 2 × 462 + 147 → 147 = 1071 % 462 1071 = 2 × 462 + 147→147=1071\%462 1071=2×462+147147=1071%462

  2. 然后从462中不断减去147直到小于147(可以减3次,即n1 = 3),余数是21:
    462 = 3 × 147 + 21 → 21 = 462 % 147 462 = 3 × 147 + 21→21=462\%147 462=3×147+2121=462%147

  3. 再从147中不断减去21直到小于21(可以减7次,即n2 = 7),没有余数:
    147 = 7 × 21 + 0 → 0 = 147 % 21 147 = 7 × 21 + 0→0=147\%21 147=7×21+00=147%21

此时,余数是 0,算法终止。所以 1071 和 462 的最大公约数是倒数第二步的余数 —— 21,这和用素因数分解得出的结果相同(见上文)。用表格表示如下:

步骤数算式商和余数
0 1071 = 462 ∗ n 0 + r 0 1071 = 462*n_{0} + r_{0} 1071=462n0+r0 n 0 = 2 , r 0 = 147 n_0=2, r_0=147 n0=2,r0=147
1 462 = 147 n 1 + r 1 462 = 147 n_{1} + r_{1} 462=147n1+r1 n 1 = 3 , r 1 = 21 n_1=3, r_1=21 n1=3,r1=21
2 147 = 21 ∗ n 2 + r 2 147 = 21*n_{2} + r_{2} 147=21n2+r2 n 2 = 7 , r 2 = 0 , 算 法 终 止 n_2=7, r_2=0,算法终止 n2=7,r2=0

3. 计算机实现
3.1 循环实现

3.1.1 伪代码

function gcd(a, b)while b ≠ 0t ← bb ← a mod ba ← treturn a

3.1.2 C++ 实现

#include <iostream>// 对应上面的算法描述,使用 p、q 作为参数输入
unsigned int gcd(unsigned int p, unsigned int q) {unsigned int temp = 0;while (q != 0) {temp = q;q = p % q;p = temp;}return p;
}int main() {std::cout << gcd(1071, 462) << std::endl;		// 21return 0;
}

3.1.3 Python 实现

def gcd(p, q):while(q != 0):temp = qq = p % qp = tempreturn pif __name__ == "__main__":print(gcd(1071, 462))

3.1.4 Java 实现

// file_name: temp.java
public class temp{static long gcd(long p, long q) {long temp = 0;while (q != 0) {temp = q;q = p % q;p = temp;}return p;}public static void main(String[] args) {System.out.println(gcd(1071, 462));  			// 21}
}

3.2 迭代实现

3.2.1 伪代码

function gcd(a, b)if b = 0return aelsereturn gcd(b, a mod b)

3.2.2 C++ 实现

#include <iostream>unsigned int gcd(unsigned int p, unsigned int q) {if (q == 0) return p;elsereturn gcd(q, p%q);
}int main() {std::cout << gcd(1071, 462) << std::endl;	return 0;
}

3.2.3 Python 实现


def gcd(p, q):if q == 0:return pelse:return gcd(q, p%q)if __name__ == "__main__":print(gcd(1071, 462))

3.2.4 Java 实现

// file_name: temp.javapublic class temp{static long gcd(long p, long q) {if (q == 0) {return p;}else {return gcd(q, p%q);}}public static void main(String[] args) {System.out.println(gcd(1071, 462));}
}
http://www.lryc.cn/news/2417802.html

相关文章:

  • 视图的基本操作
  • Linux ps命令详解
  • 关于.NET、ASP.NET和ASP
  • Gson的用法详解_Gson如何进行进行序列化和反序列化
  • python的符号lt和gt怎么输入_lt;lt;Python基础教程gt;gt;学习笔记 | 第04章 | 字典...
  • 科普:SMP系统是什么
  • RISC-V CPU+GPU+AI,Imagination创新解决方案带来了哪些惊喜?
  • WebShell
  • SpringSecurity(安全)基础
  • Oracle数据库CDB与PDB
  • ubuntu搜狗输入法
  • 日期操作类(DateFormat与SimpleDateFormat)的区别和使用详解
  • Java中Map详解
  • SQL中的like语句用法
  • 仓库管理WMS软件(Warehouse Management Software)百科解析
  • 在vue中使用CKEditor4富文本编辑器
  • Unity基础三: 什么是Shader
  • CIDR 基础知识
  • SHA1 算法加密技术核心思想
  • 详解Tensorboard及使用教程
  • Android Binder机制解析
  • 【传输层协议】 TCP UDP协议 解析(一)
  • FLOPs如何计算
  • 取拼音字头
  • VB 在Visio 2010 以编程方式创建子进程图
  • 根文件系统(二):busybox
  • 浅谈NBIOT
  • 全网最全python教程,从零到精通(学python有它就够必收藏)_python学习相关博客
  • 如何使用好google学术?
  • js刷新当前页面的5种方式