我实现了以下版本的扩展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;
}
我不太擅长实现它的非递归版本,你可以帮助我吗?
答案 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;
}