1 / 10

Understanding Recursion and Tail Recursion in Programming

Recursion in programming involves a function calling itself or using itself in its definition. This concept is essential for tasks like calculating factorials. Recursion affects the call stack and performance, impacting time and memory. Tail recursion, a type of recursion where the last operation is either the base case return or the recursive call, can optimize memory usage by reusing stack frames. Modern compilers can optimize tail recursion, improving the efficiency of recursive functions.

chereji
Download Presentation

Understanding Recursion and Tail Recursion in Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CS 240 – Lecture 13 Recursion, Tail Recursion

  2. 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.

  3. 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.

  4. 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); }

  5. Recursion – How it affects the Call Stack Stack Pointer • 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. factorial(3) Stack Pointer Stack Pointer 3 Stack Pointer 2 3 1 2 3

  6. 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.

  7. 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 3rdline of the function, the last thing that the call would do is multiplication.

  8. 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 factorialHelper(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 factorialHelper(n, 1); }

  9. 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!

  10. Recursion – Tail Recursion in Memory Stack Pointer • 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. factorialHelper(3, 1) Stack Pointer a n 1 3 3 2 6 1

More Related