1

I was learning some basic algorithms then I came across Euclidean Algorithm to find GCD of two numbers.

I understood that Algorithm on paper. There is a iterative code to do the same

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; 
}

I am very comfortable with the above iterative code Then there were two more recursive versions of the same code

int gcd(int a, int b){
    if(a==b) 
        return a;
    if(a>b) 
        return gcd(a-b,b);
    return gcd(a,b-a);
}

And this is the smallest one in terms of lines]

int gcd(int a, int b){ 
    if (a == 0) 
        return b; 
    return gcd(b % a, a);
} 

From my understanding of recursion, In recursion, We try to find the answer of a complex problem (general case) using an answer we know (base case)

As the recursion calls stack up we are essentially going to simpler problems until the base case is hit. The base case returns a value, And because of that value being returnes, answers to all the stacked sub problems start bubbling up to the original function call and in the end we arrive to the answer of our problem.

I am not understanding how the value returned by base case is used by the function calls placed above

This is my attempt at dry running the above code (Third one). The function call is

gcd(20,8);

gcd(20,8) -> gcd(8,20) -> gcd(4,8) -> gcd(0,4)

Now we hit the base case with the function call gcd(0,4)

It returned 4

Now how did the previous function call gcd(4,8) use that 4

We are not 'catching' the returned value in any variable, Then what exactly happens to that value and how is the final answer (4 in this case) bubbled up and returned by the original function call?

KshitijV97
  • 347
  • 1
  • 4
  • 16
  • 2
    *"We are not 'catching' the returned value in any variable [...]"* No, but you *are* "catching" it in your `return gcd(b % a, a);` statement, which effectively says "call this function, take the value returned, and use it as my own return value (or in other words, "forward" the return value)." – Cornstalks Jul 06 '19 at 05:10
  • 1
    "_From my understanding of recursion, In recursion, We try to find the answer of a complex problem (general case) using an answer we know (base case)_" - No, you take it too far. – Ted Lyngmo Jul 06 '19 at 05:14
  • 1
    @Cornstalks Understood, So gcd(20,8) called gcd(8,20), gcd(8,20) called gcd(4,8), gcd(4,8) called gcd(0,4). gcd(0,4) returned 4 to its caller, Then 4 was returned by all these functions to their above caller. Got it. Thanks – KshitijV97 Jul 06 '19 at 05:21
  • 1
    Adding a `std::cout` before each recursive call will map what is happening for your and help you visualize the flow. When you return a value, you are done. When you return a function, control simply picks up in the new function with the new parameters. It continues until you return a value. E.g., adding `std::cout << a << " == " << b << " - returning " << a << '\n';` or, e.g. `std::cout << a << " > " << b << " - returning gcd(a-b,b)\n";`, etc.. should do the trick. – David C. Rankin Jul 06 '19 at 05:26

2 Answers2

3

Consider this example:

int functionA() {
    return functionB();
}

This code will call functionB and directly return the result of functionB to the caller of functionA without manipulating it. It is equivalent to writing:

int functionA() {
    int toReturn = functionB();
    return toReturn;
}

As you put it the value returned by functionB "is not caught" by an explicitly defined variable in functionA.

Perhaps the recursion is what confused you but your question is not actually about recursion. It is valid for any function call.

Patrick
  • 1,458
  • 13
  • 27
  • 1
    https://pastebin.com/cQbxuTMK Check this piece of code. I have implemented recursive binary search. There are two functions, One commented and the other one non commented. One has 'return' before recursive calls while the other does not, But still both of the functions work same. So does this mean that there is no need to add 'return' while calling a function recursively? – KshitijV97 Jul 07 '19 at 16:24
  • Oh ! A very interesting example, thank you. To my great surprise both code produce the same result. However you should NOT rely on this. If you fail to make an explicit return statement in a function, the behavior is undefined (meaning the compiler will return something but you cannot be sure of what it will return). It just so happens that the compiler made the 'good' choice in your particular case. Have a look at this question/answer https://stackoverflow.com/a/2784137/9070798 ! – Patrick Jul 08 '19 at 01:09
2

I think your understanding of recursion is correct and complete. You just need to learn a bit about role of Call Stack in function calls. You can find many posts in the web to grasp the concept. Here I'll try to give you a brief definition of the Call Stack concept.

Memory of a program is divided in multiple segments. Two of the most important ones are the Stack and Heap. Here we'll focus on Stack.

Every local variable and every function you call goes there. It’s where relevant information about your program goes — which functions are called, what variables you created, and some more information. This memory is also managed by the program and not by the developer. The stack is an ordered insertion place.

The stack is a LIFO (Last-In-First-Out) data structure. You can view it as a box of perfectly fitted books — the last book you place is the first one you take out. By using this structure, the program can easily manage all its operations and scopes by using two simple operations: push and pop.

enter image description here

To keep track of the current memory place, there is a special processor register called Stack Pointer. Every time you need to save something — like a variable or the return address from a function — it pushes and moves the stack pointer up. Every time you exit from a function, it pops everything from the stack pointer until the saved return address from the function.

I think now you know what happens in recursive calls. Each function has its own variables stored in the Stack. When a function reaches its return statement, pushes the result in the stack and another function which has called this function will pop the result from stack.

Now you know how call stack works. It's a key concept in understanding recursion.

Fartab
  • 4,725
  • 2
  • 26
  • 39