CS 240 Lecture 13 Recursion Tail Recursion Recursion

  • Slides: 10
Download presentation
CS 240 – Lecture 13 Recursion, Tail Recursion

CS 240 – Lecture 13 Recursion, Tail Recursion

Recursion – Recursive Calls to a Function • To review a topic you should

Recursion – Recursive Calls to a Function • To review a topic you should have covered, recursion in programming is the act of a function or procedure calling itself or otherwise making use of itself in its definition. int factorial(int n) { return (n > 1) ? n * factorial(n-1) : 1; } • Above we have an example, the canonical example of the factorial function. • factorial makes calls to itself as part of its function body, which is recursion.

Recursion – Anatomy of Recursive Functions • In programming, single recursion is the act

Recursion – Anatomy of Recursive Functions • In programming, single recursion is the act of a function directly calling itself. • factorial calls factorial. • There is also multiple recursion in which a function f calls some other function which, before terminating, eventually leads to another call to f. • No good practical examples of this to talk about just yet, but it’s very common in parsing programs and compilers. • In the end, a recursive function must have a stopping condition or it will infinitely loop.

Recursion – Anatomy of Recursive Functions • In short, a single recursive function has

Recursion – Anatomy of Recursive Functions • In short, a single recursive function has the following. • A stopping condition with a base case. • Without this, the call is infinite. • A call to the same function. • Without this, the call is not recursive. int factorial(int n) { if (n <= 1) return 1; return n * factorial(n-1); }

Recursion – How it affects the Call Stack • During a recursive call, we

Recursion – How it affects the Call Stack • During a recursive call, we create a stack frame just as we would for any other function call. • However, since we are calling the same function, every stack frame is associated with the same function. • Depending on how many iterations occur, the stack can get pretty full. Stack Pointer factorial(3) Stack Pointer 1 3 2 3

Recursion – Impact on Performance • Impact on Time • Creating and clearing stack

Recursion – Impact on Performance • Impact on Time • Creating and clearing stack frames takes time. • When you call a function, there are operations to push variables onto the stack. • You also need to push on return information and instruction addresses. • Also, when the function terminates, the stack frame needs to be removed. • Impact on Memory • As we saw before, the deeper the recursion, the more stack frames are created. • Also, infinite loops WILL result in a stack overflow unless there is some OS protection. • For these reasons, recursion should not be used in serious applications UNLESS certain optimizations are done.

Recursion – Optimizing with Tail Recursion • Tail recursion is a type of recursion

Recursion – Optimizing with Tail Recursion • Tail recursion is a type of recursion where the last thing that happens in a recursive function call is either the return of the base case or the recursive call. • The definition we had for factorial is NOT tail recursion. int factorial(int n) { if (n <= 1) return 1; return n * factorial(n-1); } • The 3 rd line of the function, the last thing that the call would do is multiplication.

Recursion – Optimizing with Tail Recursion • At first, this will look like some

Recursion – Optimizing with Tail Recursion • At first, this will look like some black magic, but the way to rewrite the factorial function in tail recursion makes use of another argument. int factorial. Helper(int n, int a) { if (n <= 1) return a; return factorial(n - 1, n * a); } • The a variable above acts as an accumulator. • You’ll need to start every call to factorial with a = 1. int factorial(int n) { return factorial. Helper(n, 1); }

Recursion – Optimizing with Tail Recursion • Why is this better? • The tail

Recursion – Optimizing with Tail Recursion • Why is this better? • The tail recursive function has already pretty much completed by the time it makes the recursive call to itself. • Because of this, the content of it’s stack frame is useless? • Why is that better? • Because the stack frame is useless, compilers can identify tail recursion and decide that they can REUSE the useless stack frame instead of creating a new one. • This solves the memory impact of recursive functions!

Recursion – Tail Recursion in Memory • Here, we calculate factorial(3) just like we

Recursion – Tail Recursion in Memory • Here, we calculate factorial(3) just like we did before, but we show the stack as we go through the iterations with tail recursion instead. • This is an optimization that most modern compilers do. • It can be turned off, so be careful. Stack Pointer factorial. Helper(3, 1) Stack Pointer a n 1 3 3 2 6 1