我刚刚发现这个算法来计算我的讲义中最大的公约数:
public static int gcd( int a, int b ) {
while (b != 0) {
final int r = a % b;
a = b;
b = r;
}
return a;
}
所以 r 是将 b 分成 a (得到mod)时的余数。然后将 b 分配给 a ,并将余数分配给 b ,并返回 a 。我不能为我的生活看到它是如何运作的!
然后,显然这个算法并不适用于所有情况,然后必须使用这个算法:
public static int gcd( int a, int b ) {
final int gcd;
if (b != 0) {
final int q = a / b;
final int r = a % b; // a == r + q * b AND r == a - q * b.
gcd = gcd( b, r );
} else {
gcd = a;
}
return gcd;
}
我不明白这背后的原因。我通常得到递归并且擅长Java,但这是在逃避我。请帮忙吗?
答案 0 :(得分:25)
Wikipedia文章包含一个解释,但要立即找到它并不容易(同时,程序+证明并不总是回答“为什么会这样做”)。
基本上,它归结为这样的事实:对于两个整数a,b(假设a> = b),总是可以写a = bq + r,其中r <1。湾
如果d = gcd(a,b),那么我们可以写a = ds和b = dt。所以我们有ds = qdt + r。由于左侧可被d整除,因此右侧也必须可被d整除。由于qdt可被d整除,因此结论是r也必须能被d整除。
总结:我们有一个= bq + r,其中r < b和a,b和r都可被gcd(a,b)整除。
因为&gt; = b&gt; r,我们有两个案例:
为什么减少?因为r <湾所以我们正在处理的数字肯定更小。这意味着我们只需要在达到r = 0之前将这种减少应用有限次数。
现在,r = a%b,希望能解释你的代码。
答案 1 :(得分:1)
他们是等同的。首先要注意的是,第二个程序中的q
根本没有使用。另一个区别是迭代与递归。
至于它的工作原理,上面链接的维基百科页面很好。第一个插图特别有效地直观地传达了“为什么”,然后下面的动画说明了“如何”。
答案 2 :(得分:0)
鉴于从未使用'q',我没有看到你的普通迭代函数和递归迭代函数之间存在差异...两者都
gdc(first number, second number)
as long as (second number > 0) {
int remainder = first % second;
gcd = try(second as first, remainder as second);
}
}
除非尝试将此应用于非整数,否则此算法会失败?
(有关详细信息,请参阅http://en.wikipedia.org/wiki/Euclidean_algorithm)
答案 3 :(得分:0)
这是一篇有趣的博文:Tominology。
在讨论欧几里德算法背后的许多直觉时,它是用JavaScript实现的,但我相信如果想要的话,将代码转换为Java并不困难。
答案 4 :(得分:-1)
Here是我发现的一个非常有用的解释。
对于那些懒得打开它的人来说,这就是它所说的:
当你必须找到(3084,1424)的GCD时,请考虑这个例子。让我们假设d是GCD。这意味着d | 3084和d | 1424(使用符号&#39; |&#39;说&#39;划分&#39;)。
遵循d | (3084 - 1424)。现在我们尝试尽可能地减少这些可被d整除的数字(在这种情况下为3084和1024),以便我们将0作为数字之一。请记住,GCD(a,0)是一个。
自d | (3084 - 1424),它遵循d | (3084 - 2(1424))
这意味着d | 236.
提示:(3084 - 2 * 1424 = 236)
现在忘记了初始数字,我们只需要解决d,我们知道d是分为236,1424和3084的最大数字。所以我们使用较小的两个数字来继续,因为它&#39; ll将问题收敛于0。
d | 1424和d | 236意味着d | (1424 - 236)。
所以,d | (1424 - 6(236))=&gt; d | 8.
现在我们知道d是划分8,236,1424和3084的最大数字。再次采用较小的数字,我们有
d | 236和d | 8,暗示d | (236 - 8)。
所以,d | (236 - 29(8))=&gt; d | 4.
再次,被d整除的数字列表会增加并收敛(数字越来越小,越接近0)。就目前而言,d是划分4,8,236,1424,3084的最大数字。
采取相同步骤,
d | 8和d | 4意味着d | (8-4)。
所以,d | (8 - 2(4))=&gt; d | 0.
可被d整除的数字列表现在为0,4,8,236,1484,3084。 (a,0)的GCD始终是a。所以,一旦你将0作为两个数字中的一个,另一个数字是原始的两个gcd和所有介于两者之间的gcd。
这正是您的代码正在做的事情。您可以将终端条件识别为GCD(a,0)= a。
另一步是找到两个数字的其余部分,然后选择前两个中的较小数字作为新数字。