Confusion with state of parameter in recursion with javascript - javascript

Gif for the debugger in console
So, when running this, i'm a bit confused how fac parameter is maintaing the state. what i understand by factorial(4) is
4 * (4-1) // 4 * 3 = 12
12 * (3-1) // 12 * 2 = 24
24 * (2-1) // 24 * 1 = 24
function factorial(fac){
debugger
if(fac == 1)
return fac
return fac * factorial(fac-1)
}
factorial(4)

Every call to factorial has its own fac parameter, with its own value. So when, in the first call (during factorial(4)), when you do:
return fac * factorial(fac - 1);
that calls factorial again, passing in the value resulting from fac - 1 (3). That new call receives fac = 3 and does its work with it. While that's happening, the first call is waiting to get the return value from it (let's call it retVal) so it can finish the return fac * ____________ by plugging retVal in where ____________ is.
Eventually, a call to factorial does its work by returning fac instead of calling factorial again, which means the one that called it can complete its work and return its return value, which means the one that called it can do that, until we get back to the top one that returns the overall result.
Here's an attempt to show how the calls stack up (using indentation for showing the recursive calls):
factorial(fac = 4)
factorial(fac = 3)
factorial(fac = 2)
factorial(fac = 1)
return 1
|
v
return 2 * 1 = 2
|
+−−−−−−−+
|
v
return 3 * 2 = 6
|
+−−−−−−−+
|
v
return 4 * 6 = 24
Note that when factorial(1) is running, there are four different fac parameters in memory, fac = 4 (the outermost call), fac = 3 (the first recursive call), fac = 2 (the next recursive call), and fac = 1 (the last recursive call before the returns kick in).

Think of the function calls as stack, so when fac(4) is called this stack is formed
factorial(1)
^
Calls^
^
factorial(2)
^
Calls^
^
factorial(3)
^
Calls^
^
factorial(4)
then this stack is resolved from top down. so value of fac is being changed at every call
factorial(1) ==> fac = 1, return value =1
then resolves
factorial(2) ==> fac = 2, return value =2*factorial(1) > already in memory
then resolves
factorial(3) ==> fac = 3, return value =3*factorial(2) -> in memory
then resolves
factorial(4) ==> fac = 4, return value =4*factorial(3) -> in memory

You can simplify pure expressions the same way you can simplify mathematical expressions.
factorial(4)
= 4 * factorial(4 - 1) // because 4 != 1
= 4 * factorial(3)
= 4 * (3 * factorial(3 - 1)) // because 3 != 1
= 4 * (3 * factorial(2))
= 4 * (3 * (2 * factorial(2 - 1))) // because 2 != 1
= 4 * (3 * (2 * factorial(1)))
= 4 * (3 * (2 * 1)) // because 1 == 1
= 4 * (3 * 2)
= 4 * 6
= 24
This is a very powerful way of reasoning about expressions. It's one of the advantages of writing pure code instead of impure code. You can't simplify impure expressions in this manner because impure code has side effects which need to be tracked.
Anyway, why don't you try to simplify the following result expression by yourself? It'll help you understand how recursion works in functional programs. No need to think about function call stacks or anything else technical. Just get a pen and paper and start simplifying the expression like you would do in your 5th grade math class.
function fib(n) {
if (n === 0) return 1;
if (n === 1) return 1;
return fib(n - 1) + fib(n - 2);
}
const result = fib(5);
console.log(result); // 8
A few tips to remember.
When replacing a function call with its result, wrap it in parentheses.
Always simplify the leftmost expression first. This mimics the way JavaScript works.
Simplify expressions one at a time. Don't simplify multiple expressions in a single step.

Related

How do I understand this Recursion Base Code Problem

I'm learning the recursion concept in js, I got a very basic question of the base code returning problem.
function factorial(n) {
if (n === 1) {
return 1;
}
return n * factorial(n - 1);
}
So this is a simple factorial example of explaining the recursion.
factorial(5) = 120
My question is, why it's not returning 1 when the n reaches 1? After the return inside the if statement, the second return will continue to run? And if it return 1, the second return continue to run and it will do 5 * 1 forever (let's say n reaches 5)???
I made a small example, adding some log's. The attribute indent was added to help on logs indentation, and for better understand what's happen.
On recursive calls (like on non recursive calls), when outer function calls the inner function, the current variables are stored somewhere on memory (on one stack), and then call the function.
When the inner function returns, the values will be restored.
If you see the log's of my example, the parameter n decrease the value on each call, but was restored after the inner function returns.
Answering to your questions:
My question is, why it's not returning 1 when the n reaches 1?
when the n reaches 1, the function returns 1, but that result will applied on de factorial(2), that are waiting at that moment for the result, and so on.
After the return inside the if statement, the second return will continue to run?
Yes, the second if statement will continue to run, but it's like on other instance, that was waiting for the result.
And if it return 1, the second return continue to run and it will do 5 * 1 forever (let's say n reaches 5)???
No. The n will be multiplied with the result of next call (the outer call waits for the inner call):
5 * factorial(4)
4 * factorial(3)
3 * factorial(2)
2 * factorial(1)
1
2 * 1 = 2
3 * 2 = 6
4 * 6 = 24
5 * 24 = 120
function factorial(n, indent) {
if (!indent) indent = '';
console.log(indent+'BEGIN: factorial('+n+')');
if (n === 1) {
console.log(indent+'END: factorial('+n+'): 1');
return 1;
}
let factorialNMinus1 = factorial(n - 1, indent + ' ');
let result = n * factorialNMinus1 ;
console.log(indent+'END: factorial('+n+'): ' + n + ' * ' + factorialNMinus1 + ' = ' + result);
return result;
}
console.log('result = ' + factorial(5));
A good way of analyzing recursion is by using a simple situation, and think how the recursion will unfold.
Lets say n = 3.
function factorial(n) {
if (n === 1) {
return 1;
}
return n * factorial(n - 1);
}
console.log(factorial(3));
So, the following iterations will happen:
fac(3) == 3 * fac(3-1)
fac(3-1) == 3-1 * fac(2-1)
fac(2-1) == 2-1 * 1
The condition that makes the recursion unfold and start returning is n == 1, so when that happens, the last function call will return 1 instead of calling itself again.
But the actual result will be the sum of all returned operations: (3 * ((3-1) * ((2-1) * 1)))
So, factorial(5) returns 120 because: (5 * ((5-1) * ((4-1) * ((3-1) * ((2-1) * 1))))) == 120.

Dont understand the next iteration for recursion

I'm learning to work with recursion and so far it went well with basic examples. However I want to calculate the factorial, but I don't understand what happened step-by-step. If I do it imperatively I understand it but I fail on this example:
return x * fac(x-1); gives me back 5 * 4, so far soo good, but what happens now? Does it mean it become 20 now? So my next iteration would be then 20 * 19?
const fac = (x) => {
if(x <= 1) {
return x;
}
return x * fac(x-1);
};
console.log(fac(5)); // 120
just walk through the logic.
1. fac(5) yields 5 * fac(4)
2. fac(4) yields 4 * fac(3)
3. fac(3) yields 3 * fac(2)
4. fac(2) yields 2 * fac(1)
5. fac(1) yields 1
substituting from bottom to top, you get
fac(5) = 5 * 4 * 3 * 2 * 1
I think i understand that part now and the difference between 4 and fac(4). The steps look like:
5. 5 * // ()
4. 4 * // (20)
3. 3 * // (60)
2. 2 * // (120)
1. 1 * // (120)
However, I have another example which i cant resolve step by step, while i can see the logic in the imperatively programming.
let fibo = (x) => {
if(x<=2) {return 1;}
return fibo(x-1) + fibo(x-2);
};
console.log(fibo(4)); //3
I cant resolve step by step what return fibo(x-1) + fibo(x-2); values this gives me each step. On the imperatively programming it is
function fibonacci(num){
var a = 1, b = 0, temp;
while (num >= 1){
temp = a;
a = a + b;
b = temp;
num--;
}
return b;
}
console.log(fibonacci(4); // 3
where the steps would be like
4. b = 1
3. b = 1
2. b = 2
1. b = 3

What is a non-mathematical explanation for the Big O of recursive fibonacci?

I read both articles on Big O for Recursive Fibonacci sequence but still do not have a conceptual understanding of why it is O(2^n).
This is not a duplicate of this link. Please don't mark as a duplicate. I'm looking for a conceptual answer.
This is one of the simplest recursive functions out there and I want to understand how to look at it and determine the the Big O without complex math and proofs.
// O(2^n)
function fiboR(n){
if( n === 0 || n === 1 ){
return n;
} else if ( n >=2 ){
return fiboR(n-1) + fiboR(n-2);
}
}
For example Big O for the iterative version is O(n). I can just look and see that as n increases the while loop iterations increase linearly. No complex math or long proofs needed.
// O(n)
function fibo(n){
let prev0 = 0;
let prev1 = 1;
if( n === 0 || n === 1 ){
return n;
}
while( n-- >= 2){
sum = prev0 + prev1;
prev0 = prev1;
prev1 = sum;
}
return sum;
}
It is simple to calculate by diagraming function calls. Simply add the function calls for each value of n and look at how the number grows.
The Big O is O(Z^n) where Z is the golden ratio or about 1.62.
Both the lenoardo numbers and the fibonacci numbers aproach this ratio as we increase n.
2 (2 -> 1, 0)
4 (3 -> 2, 1) (2 -> 1, 0)
8 (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
(2 -> 1, 0)
14 (5 -> 4, 3) (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
(2 -> 1, 0)
(3 -> 2, 1) (2 -> 1, 0)
22 (6 -> 5, 4)
(5 -> 4, 3) (4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
(2 -> 1, 0)
(3 -> 2, 1) (2 -> 1, 0)
(4 -> 3, 2) (3 -> 2, 1) (2 -> 1, 0)
(2 -> 1, 0)
A good number of naive recursive functions have exponential complexity, so this is good intuition to keep in mind.
Consider this function:
function fiboR1(n){
if( n === 0 || n === 1 ){
return n;
} else if ( n >=2 ){
return fiboR1(n-1) + fiboR1(n-1);
}
}
Okay, so fiboR1 doesn't actually compute the Fibonacci sequence. That doesn't matter. Notice that its asymptotic complexity will be at least that of fiboR. This is because the two recursive calls to fiboR1(n-1) are more expensive than one call to fiboR(n-1) and one call to fiboR(n-2). So let's think about what the complexity of fiboR1 is.
Let's consider an example call to fiboR1(100).
fiboR1(100) = 2 * fiboR1(99)
= 4 * fiboR1(98)
= 8 * fiboR1(97)
= 16 * fiboR1(96)
= 32 * fiboR1(95)
= 64 * fiboR1(94)
...
See the pattern now? We have O(2^n) recursive calls to fiboR1, and each call is a constant time branch. So fiboR1 is O(2^n), which means that by extension, fiboR is also O(2^n), as big-O is an upper-bound function.
If you know the closed form for the Fibonacci sequence, we can also just do this example for fiboR directly. Let's consider fiboR(100):
fiboR(100) = fiboR(99) + fiboR(98)
= 2 * fiboR(98) + fiboR(97)
= 3 * fiboR(97) + 2 * fiboR(96)
= 5 * fiboR(96) + 3 * fiboR(95)
= 8 * fiboR(95) + 5 * fiboR(94)
= 13 * fiboR(94) + 8 * fiboR(93)
...
The number of recursive function calls follows the Fibonacci sequence. The closed form for the Fibonacci sequence is exponential in n. In fact, it is O(((1+sqrt{5})/2)^n), which is about O(1.6^n).
Assuming you accept that the function is correct, i.e. that it does calculate the Fibonacci numbers, then it is very easy to show that its running time must be exponential: it only returns 0 or 1 in the base case, and it only produces larger results by adding smaller results together.
Since the Fibonacci numbers grow exponentially, the only way you could make them by adding a lot of 1s together is by adding exponentially many 1s. Each result only gets added to the final total once, so the base case must be executed exponentially many times to produce all of those 1s as different results.

Understanding one example in the Eloquent JS 3th edition

If I put return (n-1)*n that is 8-1=7*8=56
But if I put like in the book example return factorial(n-1)*n then it returns 40320.
How does the calculation/math works? It returns a function, it return itself - right?
But I don't know how this works. How does it get to the number 40320?
const factorial = function(n) {
if (n === 0) {
return 1
} else {
return factorial(n - 1) * n
}
}
console.log(factorial(8))
We can calculate the factorial of any natural number (n) by doing:
n! = n * n-1 * n-2 * n-3 * ... * 1
Eg:
4! = 4 * 3 * 2 * 1 = 24
This can be simplified to:
n! = n * (n-1)!
Eg:
4! = 4 * (4-1)! = 4 * 3!
3! = 3 * (3-1)! = 3 * 2!
2! = 2 * (2-1)! = 2 * 1!
1! = 1 * (1-1)! = 1 * 0!
0! = 1
So solving this, we can now work back up our equations:
0! = 1
1! = 1 * 0! = 1 * (1) = 1 // <--- subbing in as we now know the result of 0! to be 1
2! = 2 * 1! = 2 * (1) = 2
3! = 3 * 2! = 3 * (2) = 6
4! = 4 * 3! = 4 * (6) = 24
When we do this with code, we can use recursion. This means we call a function within itself. Taking the above example we can do this using a function called fact() instead of using the ! notation:
fact(4) = 4 * fact(4-1) = 4 * fact(3) // same as: 4! = 4 * (4-1)! = 4 * 3!
So after running fact(4), we see that we are returning / trying to calculate the result of 4 * fact(3). But we don't know what fact(3) is yet, so we need to calculate it:
fact(3) = 3 * fact(3-1) = 3 * fact(2)
Here we are trying to calculate 3 * fact(2), but we don't know what fact(2) is yet, so we need to work it out:
fact(2) = 2 * fact(2-1) = 2 * fact(1)
Again, we need to work out what fact(1) is:
fact(1) = 1 * fact(1-1) = 1 * fact(0)
Lastly, we need to work out what fact(0) is:
fact(0) = 1
Here we get fact(0) is equal to 1. Notice how fact(0) returns a value which doesn't have a reference to another fact call. This means that we have reached our base case (defined in your if(n===0)) and can now calculate/traverse our previous equations we didn't know how to answer.
So going back up to fact(1) we now replace the call to fact(0) with 1
fact(1) = 1 * fact(0) 1 = 1
Now we know what fact(1) is, we can now calculate fact(2):
fact(2) = 2 * fact(1) 1 = 2
Now we know what fact(2) is, we can calculate fact(3):
fact(3) = 3 * fact(2) 2 = 6
Lastly, we can calculate fact(4):
fact(4) = 4 * fact(3) 6 = 24
So, using this, we get fact(4) = 24
This is the basis of how this recursive function works.
So if you use return (n-1)*n at the end of your function instead of return fact(n-1) * n you are simply just doing one return, and not calling your function again to calculate the factorial of n-1.
It returns factorial(n-1)*n instead of (n-1)*n, hence the calculation would not be just 8*7 = 56. Instead, since it is returning a call to itself, the final calculation would be 8*7*6*5*4*3*2*1 = 40320.
This is called a recursive function. When you called factorial(8), it will return factorial(7)*8, which called factorial(7) before returning. factorial(7) returns factorial(6)*7, which called factorial(6) before returning. This goes all the way until factorial(2) returns factorial(1)*1, which called factorial(1) that returns 1.
Then factorial(2) returns factorial(1)*2 = 1*2 = 2, factorial(3) returns factorial(2)*3 = 2*3 = 6, factorial(4) returns factorial(3)*4 = 6*24 = 24, and so on. Lastly, factorial(8) returns factorial(7)*8 = 5040*8 = 40320

Am I wrong to feel this recursive function feels like a 'for loop?' [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
Can someone explain how this recursive function produces 5 * 4 * 3 * 2 * 1 to get 120?
var factorial = function(n){
if (n === 0)
return 1;
else
return n * factorial(n - 1);
};
factorial(5); // spits out 120
If we use 5 like like in the example, once we got to the else statement wouldn't
return n * factorial(n - 1);
translate to 'return 5 multiplied by the factorial function(5-1); 5 times...
Am I wrong to feel this recursive function feels like a 'for loop?'
No, recursion and loops have a lot in common. In particular, it's very important that they both have a termination condition. :-) In this case, that termination condition is n === 0.
The best way to understand this is to single-step through the code in a debugger. Your browser has one, so you could put that code in a page and load it and walk through it.
To get you started:
You call factorial(5). Since n is not === 0, factorial calls itself with n - 1 (4)
Now we've recursed one level, and we're running factorial(4) (the call to factorial(5) still hasn't returned, it's waiting on us). Since n is not === 0, we call factorial(3) and wait for it to return.
...rinse, repeat until factorial(0) is called. Since n === 0 is true (at that point, there are five calls to factorial outstanding and stacked up), factorial(0) returns 1, and we can start unwinding the stacked up calls.
Now factorial(1) can finish by multiplying the result it got from factorial(0) by its copy of n (1) and returning that.
...which lets factorial(2) finish and multiply that by 2...
...rinse repeat...
Or to put it another way showing the nesting (recursion):
factorial(5)
return 5 * factorial(4)
return 4 * factorial(3)
return 3 * factorial(2)
return 2 * factorial(1)
return 1 * factorial(0)
return 1
And because you can't get enough diagrams (or at least I can't):
factorial(5) factorial(4) factorial(3) factorial(2) factorial(1) factorial(0)
calls ---------->
calls ---------->
calls ---------->
calls ---------->
calls ----------->
n is 0, so
returns 1
|
returns 1 * 1<-----------+
= 1
|
returns 2 * 1<------------+
= 2
|
returns 3 * 2<------------+
= 6
|
returns 4 * 6<------------+
= 24
|
returns 5 * 24<-----------+
= 120
Result: 120
Side note: That function doesn't allow for negative numbers; it could probably use a guard at the beginning...
The n changes:
5 * factorial(5-1) = 5 * 4 * factorial(4-1) = 5 * 4 * 3 * factorial(3-1) = 5 * 4 * 3 * 2 * factorial(1-1) = 5 * 4 * 3 * 2 * 1
Also to make this function better you could stop it when n is equal to 1, since the factorial of 1 is 1:
var factorial = function(n){
if (n === 1 || n === 0)
return 1;
else
return n * factorial(n - 1);
};
This function says: if you want to calculate factorial(5), well, that's really just
5 * factorial(4)
and if you want to calculate factorial(4), that's really just 4 * factorial(3)
5 * 4 * factorial(3)
and the thing about factorial(3) is that it's really just 3 * factorial(2)
5 * 4 * 3 * factorial(2)
and so on. But when you get down to factorial(0), the function finally stops (because of the if n == 0 case) and returns 1, without any further recursion. So you get
5 * 4 * 3 * 2 * 1
return n * factorial(n - 1) translates to (on the first run), "return (5 * 4!)". It doesn't do anything 5 times.
If we use 5 like like in the example, once we got to the else statement wouldn't
return n * factorial(n - 1);
translate to 'return 5 multiplied by the factorial function(5-1); 5 times...
No, it would translate to 'return n multiplied by the factorial function (n-1)' (5 times, because n starts at 5, decrements and enters the else clause until it reaches 0).
When you first enter the function, n is equal to 5.
The if clause checks if n is equal to 0. It isn't, so it goes to:
The else clause. Which translates to 'return 5 multiplied by the factorial function (which you're in) (5 - 1).
When you enter the factorial function, n is now 4.
Repeat all of those steps until n is equal to 0. The if clause will then be true and the function will return 1.
So 1 is returned from factorial(0). Factorial(1) returns 1 * factorial(0), so 1 * 1 = 1.
Factorial(2) returns 2 * factorial(1), so 2 * 1 = 2.
Factorial(3) returns 3 * factorial(2), so 3 * 2 = 6.
Factorial(4) returns 4 * factorial(3), so 4 * 6 = 24.
Factorial(5) returns 5 * factorial(4), so 5 * 24 = 120.

Categories

Resources