扩展的欧几里得算法——递归与非递归实现
来源:互联网 发布:网络诈骗事件 编辑:程序博客网 时间:2024/05/18 01:20
扩展的欧几里得算法(一)——引子
前言
欧几里得算法的目的是求出正整数a,b的最大公因数,记作gcd(a, b)。该算法的原理我就不赘述了,任何一本初等数论的课本都会有详细的介绍。这次的一系列文章的重点放在如何用实际的代码去实现这些算法,我们忽略数学的细节,专注于代码的编写。
欧几里得算法的实现非常简单,它的递归实现为
int gcd(int a, int b){ return (b == 0) ? a : gcd(b, a % b);}
同一种算法,可以有不同的实现,欧几里得算法就是这样一个活生生的例子。用递归实现的好处在于代码简洁明了,清晰易懂,只不过由于调用栈的原因,时间上不如非递归算法高效。我们也可以用非递归算法实现欧几里得算法。
int gcd(int a, int b){ if (b == 0) return a; int r = a % b; while (r) { a = b; b = r; r = a % b; } return b;}
那么什么是扩展的欧几里得算法呢?最大公因数有这样一条性质:存在整数x,y使得 ax + by = gcd(a, b)
扩展的欧几里得算法可以求出满足条件的一组x和y,当然这样的整数对(x, y)不是唯一的。
实现
在讲述扩展的欧几里得算法原理之前,我先给出实现,这样没有耐心的小伙伴可以直接从我这里copy代码过去,这也算是功德一件(笑)。
扩展的欧几里得算法常见的实现应该是一面的递归实现,它的原理非常简单。要求出整数对(x,y)满足 ax + by = gcd(a, b),(b != 0)
那么只要知道(x’, y’)满足(a % b)x' + by' =gcd(a, b)
又有a % b = a - (a / b)*b, (这里的'/'号向下取整)
我们可以知道x = x', y = y'-(a/b)x'
递归实现如下:
int e_gcd(int a, int b, int *x, int *y){ if (b == 0) { *x = 1; *y = 0; return a; } else { int r = e_gcd(b, a%b, y, x); *y -= (*x)*(a/b); return r; }}
当然,扩展欧几里得算法也有非递归实现,它的原理是“列表法”。下面给出实现代码。
int e_gcd(int a, int b, int *x, int *y){ int r, q, s1 = 1, s2 = 0; if (b == 0) { *x = 1; *y = 0; return a; } *x = 0, *y = 1; r = a % b; q = a / b; while (r) { int m = *x, n = *y; *x = s1 - (*x)*q; *y = s2 - (*y)*q; s1 = m; s2 = n; a = b; b = r; q = a / b; r = a % b; } return b;}
我们可以看出,在代码实现上,扩展欧几里得算法只是在欧几里得算法的基础上增加了对整数对(x,y)的迭代求解而已。总体来说,实现难度不大。
下回预告
- 到底什么是“列表法”求整数对(x,y)?
- 列表法的原理是什么?
- 如何在纸上用列表法求出x, y
请期待我的下一篇博文吧!下次我们接着聊。
- 扩展的欧几里得算法——递归与非递归实现
- 扩展欧几里得算法的非递归实现的证明
- 欧几里得算法求最大公约数的递归和非递归实现
- 【二叉树遍历算法】——前/中/后序递归与非递归的实现
- 递归到非递归转换——归并排序与快排的非递归实现
- 全排列算法的递归与非递归实现
- 全排列算法的递归与非递归实现
- 二叉树的递归遍历与非递归算法实现
- 二叉树的递归遍历与非递归算法实现
- 二分查找算法的递归与非递归实现
- 全排列算法的递归与非递归实现
- 全排列的递归与非递归算法实现
- 二叉树算法的实现(递归与非递归)
- 二分查找算法的递归与非递归实现
- Fibonacci数列的递归与非递归实现算法详解
- C++ - 扩展欧几里德算法非递归实现
- 递归与非递归算法的分析
- Ackerman的递归与非递归算法
- stat函数学习引申
- Python面向对象编程(3)——类方法、静态方法
- hadoop2.7 伪分布
- CNN学习报告
- Sleeping会话导致阻塞原理(下)
- 扩展的欧几里得算法——递归与非递归实现
- C#中虚函数的使用注意事项
- SQL SET NOCOUNT ON;
- threejs指定对象旋转中心
- Use MFC in a Static Library 和 use MFC in a Shared DLL 的区别
- OCR谷歌开源项目使用流程说明
- 漫步数学分析二十七——Stone-Weierstrass定理
- CentOS 7 巨大变动之 systemd 取代 SysV的Init
- 交叉熵代价函数