我正在学习一些基本算法,然后遇到了欧几里得算法,找到了两个数字的GCD。
我在纸上理解算法。 有一个重复的代码可以做到这一点
int euclid_gcd(int a, int b){
int dividend = a>=b ? a : b;
int divisor = a<=b ? a : b;
while(divisor!=0){
int remainder = dividend % divisor;
dividend = divisor;
divisor = remainder;
}
return dividend;
}
我对上面的迭代代码非常满意 再有两个递归版本相同的代码
int gcd(int a, int b){
if(a==b)
return a;
if(a>b)
return gcd(a-b,b);
return gcd(a,b-a);
}
这是行中最小的一个]
int gcd(int a, int b){
if (a == 0)
return b;
return gcd(b % a, a);
}
根据我对递归的理解,在递归中,我们尝试使用已知的答案(基本案例)找到复杂问题的答案(通用案例)
随着递归调用的堆积,从本质上讲,我们将解决一些更简单的问题,直到基本情况发生为止。基本情况返回一个值,由于返回了该值,所有堆叠子问题的答案开始冒泡到原始函数调用,最后我们得到了问题的答案。
我不了解上面的函数调用如何使用基本情况返回的值
这是我尝试空运行上面的代码(第三步)。函数调用是
gcd(20,8);
gcd(20,8)-> gcd(8,20)-> gcd(4,8)-> gcd(0,4)
现在我们通过函数调用gcd(0,4)
它返回了4
现在,上一个函数调用gcd(4,8)
如何使用4
我们没有在任何变量中“捕获”返回的值,那么该值究竟发生了什么,最终答案(在这种情况下为4)如何起泡并由原始函数调用返回?
答案 0 :(得分:2)
考虑以下示例:
int functionA() {
return functionB();
}
此代码将调用functionB
,并将functionB
的结果直接返回给functionA
的调用者,而无需对其进行操作。相当于写:
int functionA() {
int toReturn = functionB();
return toReturn;
}
正如您所说的那样,functionA
中显式定义的变量“未捕获” functionB返回的值。
也许递归使您感到困惑,但是您的问题实际上与递归无关。它对任何函数调用均有效。
答案 1 :(得分:2)
我认为您对递归的理解是正确和完整的。您只需要了解有关 Call Stack 在函数调用中的作用。您可以在网上找到许多帖子来掌握这一概念。在这里,我将为您简要介绍调用堆栈概念。
程序的存储器分为多个段。最重要的两个是 Stack 和 Heap 。在这里,我们将重点放在 Stack 。
每个局部变量和您调用的每个函数都去了那里。您可以在其中找到有关程序的相关信息,包括调用哪些函数,创建的变量以及更多信息。该内存也由程序而非开发人员管理。堆栈是有序的插入位置。
堆栈是LIFO(后进先出)数据结构。您可以将其视为一盒完美匹配的书籍-您放置的最后一本书是您取出的第一本书。通过使用这种结构,程序可以通过使用两个简单的操作:push和pop轻松管理其所有操作和范围。
要跟踪当前的内存位置,有一个特殊的处理器寄存器,称为堆栈指针。每当您需要保存某些内容(例如变量或函数的返回地址)时,它都会向上推并向上移动堆栈指针。每次退出函数时,它都会从堆栈指针弹出所有内容,直到从函数保存的返回地址为止。
我认为现在您知道递归调用中会发生什么。每个函数在堆栈中都有自己的变量。当一个函数到达其return语句时,将结果压入堆栈,另一个调用该函数的函数将从堆栈中弹出结果。
现在,您知道调用堆栈如何工作。这是理解递归的关键概念。