c++中扩展欧几里得算法的递归到底发生了啥?

Posted

技术标签:

【中文标题】c++中扩展欧几里得算法的递归到底发生了啥?【英文标题】:What exactly happens inside extended euclidean algorithm's recursion in c++?c++中扩展欧几里得算法的递归到底发生了什么? 【发布时间】:2016-03-09 06:20:53 【问题描述】:

我知道什么是扩展欧几里得算法以及为什么要在编程中使用它。它是一种非常有用的算法,用于求数的反模。我知道如何在 c++ 中实现它,这就是我在下面用 c++ 实现它的方式。

typedef pair<int, int> pii;

#define x first
#define y second

pii extendedEuclidean(int a, int b)

    if(b==0)
        return a,0;
    else 
        pii d = extendedEuclidean(b, a%b);
        return d.y, d.x - (d.y*(a/b));
    

现在,如果我想找到一个数字的反模,例如 13,其中 mod 是例如 1000007,那么我只需调用这个函数

pair<int, int> res = extendedEuclidean(13, 1000007);

那么结果就是

res.first

我的问题是为什么以及在这个递归中究竟发生了什么?以及为什么它会产生正确的结果。

注意:这里 gcd(a, b) 必须为 1。

【问题讨论】:

它完全按照代码所说的那样做。 :/. 你不理解算法或者为什么你写的代码实现了那个算法? 当你写“我知道如何在 C++ 中实现它”时,这是否意味着你自己实现了这个,或者只是你知道一个代码被剪掉了?在前一种情况下,您应该提供有关结果的第二个元素的一些信息。否则,您应该命名您的来源。 【参考方案1】:

欧几里得算法计算一对数字(a, b)的最大公约数(假设a&gt;b)。它使用ab 的任何公约数也是a-b 的除数的观察。原因如下:

d 成为除数。然后,a 可以表示为a=d*k 用于整数kb=d*l 用于整数l。然后,a-b=d*k-d*l=d*(k-l)k-l 又是一个整数。因此,d 必须是a-b 的除数。

算法的作用是尽可能频繁地从较大的数字中减去较小的数字。这是a%b 的部分。例如。如果a = 25b = 7a%b=4 就是从a 中减去b 3 次后得到的结果。之后,新的a 将小于b。因此,您交换两个数字。这是您调用递归的部分:extendedEuclidean(b, a%b);

扩展的欧几里得算法做得更多。此外,它还计算两个数字xy,例如gcd(a, b) = x * a + y * b。这是如何完成的:

在最后一次迭代中,您最终得到a'=gcdb'=0。因此,您有gcd=a' * 1 + b' * 0,其中10 分别是x'y'。假设上一次迭代中的值为a''b''。然后我们知道a'=b''b'=a'' % b''。有了这个,我们发现b'=a''-(a''/b'')*b''(尽可能经常减去)。我们可以修改

gcd = a' * x' + b' * y'
gcd = b'' * x' + (a''-(a''/b'')*b'') * y'
    = a'' * y' + b'' * (x' - y' * (a''/b''))

因此,新的x''=y'y''=x' - y' * (a''/b'')。这是您的退货声明return d.y, d.x - (d.y*(a/b));

一个例子:

a=25, b=7。第一遍计算ab 列(从上到下)。这说明了递归调用。第二遍计算xy 列(从下到上)。这说明了返回语句:

 a  | b            |  x   | y                     | means
----+--------------+------------------------------+---------------------
 25 |  7           |  2   | -1 - 2 * (25/7) = -7  | 1 = 2 * 25 - 7 * 7 
  7 |  25 % 7 = 4  | -1   |  1 + 1 * (7/4)  =  2  | 1 = (-1) * 7 + 2 * 4
  4 |  7 % 4  = 3  |  1   |  0 - 1 * (4/3)  = -1  | 1 = 1 * 3 - 1 * 3
  3 |  4 % 3  = 1  |  0   |  1 - 0 * (3/1)  =  1  | 1 = 0 * 3 + 1 * 1
  1 |  3 % 1  = 0  |  1   |  0                    | 1 = 1 * 1 + 0 * 0

所以你得到1 = 2 * 25 - 7 * 7,其中2 是结果的.first-7 是结果的.second。如果我们在mod 25,这简化为:

1 == 2 * 0 - 7 * 7
1 == -7 * 7

因此,-7 == 18(即result.second)是7 (mod 25) 的乘法逆元。请注意,我交换了输入以避免不必要的第一次迭代。否则为result.first

【讨论】:

以上是关于c++中扩展欧几里得算法的递归到底发生了啥?的主要内容,如果未能解决你的问题,请参考以下文章

欧几里德算法与扩展欧几里德算法

数论扩展欧几里得算法

扩展欧几里得算法(解不定方程)

最大公约数与扩展欧几里得算法

扩展欧几里得算法详解

扩展欧几里得