扩展的Euclid算法 - 是否存在非递归版本?

时间:2014-04-10 14:31:25

标签: algorithm recursion

我实现了以下版本的扩展Euclid算法:

long gcdex(const long& a, const long& b, long& x, long& y)
{
    if (a == 0) {
        x = 0; y = 1;
        return b;
    }

    long x1, y1;
    long d = gcdex(b % a, a, x1, y1);
    x = y1 - (b / a) * x1;
    y = x1;
    return d;
}

我不太擅长实现它的非递归版本,你可以帮助我吗?

3 个答案:

答案 0 :(得分:1)

任何递归算法都可以使用迭代和附加堆栈实现为非递归。这仍然会导致某些算法的可读性降低,并且可能无法提高效率。

我喜欢你的算法版本 - 它简短易读(可能你需要重命名一些变量),它会为你提供最佳的算法复杂性。

答案 1 :(得分:1)

无需扩展和递归即可实现扩展的euklidian算法:


# Just a wrapper class to represent extended euklidian algorithm result
class GCD_Result:
    def __init__(self, gcd, u, v):
        self.gcd = gcd
        # u and v are the linear combination coefficients
        self.u = u
        self.v = v
    def __str__(self):
        return str(self.gcd) + " = " + str(self.u) + " * a + " + str(self.v) + " * b"

def extended_gcd(a, b):
    if a == 0:
        return GCD_Result(b, 0, 1)

    unPrev = 1
    vnPrev = 0
    unCur = 0
    vnCur = 1

    while b != 0:
        bn = a // b
        newB = a % b
        a = b
        b = newB

        # Update coefficients
        unNew = unPrev - bn * unCur
        vnNew = vnPrev - bn * vnCur

        # Shift coefficients
        unPrev = unCur
        vnPrev = vnCur
        unCur = unNew
        vnCur = vnNew

    return GCD_Result(a, unPrev, vnPrev)

在没有堆栈的情况下很难实现此算法,因为在退出递归调用时,通常进行向后替换。通过这样做,我们使算法成为非尾递归的。我的算法要做的是随着a和b的更新逐步更新系数。

答案 2 :(得分:0)

正如Ivaylo Strandjev所说,任何递归算法都可以使用迭代和附加堆栈实现为非递归。 但是对于某些问题,我们可以使用一些特殊技能来实施。对于这个问题,我们可以借助线性代数来计算x和y。

// non-recursive
void gcd_exd_non_rec(int a, int b, int &x, int &y) {
     std::vector<std::vector<int>> vec(2);
     vec[0] = {1, 0, a};
     vec[1] = {0, 1, b};
     while (vec[1][2]) {
         int q = vec[0][2] / vec[1][2];
         std::vector<int> tmp_0 = vec[1];
         // just a vector arithmetic: vec[0] - q * vec[1]
         std::vector<int> tmp_1 = {vec[0][0] - q * vec[1][0], vec[0][1] - q * vec[1][1], vec[0][2] - q * vec[1][2]};
         vec[0] = tmp_0;
         vec[1] = tmp_1;
     }
     x = vec[0][0];
     y = vec[0][1];
     return;
 }