Introduction to recursion and recursive algorithms
Sponsored Links
This presentation is the property of its rightful owner.
1 / 42

Introduction to Recursion and Recursive Algorithms PowerPoint PPT Presentation

  • Uploaded on
  • Presentation posted in: General

Introduction to Recursion and Recursive Algorithms. CS2110. Different Views of Recursion. Recursive Definition : n! = n * (n-1)! (non-math examples are common too) Recursive Procedure : a procedure that calls itself.

Download Presentation

Introduction to Recursion and Recursive Algorithms

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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript

Introduction to Recursion andRecursive Algorithms


Different Views of Recursion

Recursive Definition: n! = n * (n-1)! (non-math examples are common too)

Recursive Procedure: a procedure that calls itself.

Recursive Data Structure: a data structure that contains a pointer to an instance of itself:

public class ListNode {

Object nodeItem;

ListNode next, previous;


Recursion in Algorithms

  • Recursion is a technique that is useful

    • for defining relationships, and

    • for designing algorithms that implement those relationships.

  • Recursion is a natural way to express many algorithms.

  • For recursive data-structures, recursive algorithms are a natural choice

What Is Recursion?

  • A Definition Is Recursive If It Is Defined In Terms Of Itself

    • We use them in grammar school e.g. what is a noun phrase?

      • a noun

      • an adjective followed by a noun phrase

    • Descendants

      • the person’s children

      • all the children’s descendants

What Is Recursion?

  • Think self-referential definition

  • A definition is recursive if it is defined in terms of itself

    • Exponentiation - x raised to the y power

      • if y is 0, then 1

      • otherwiseit’s x * (x raised to the y-1 power)

Other recursive definitions in mathematics

  • Factorial:n! = n (n-1)! and 0! = 1! = 1

  • Fibonacci numbers: F(0) = F(1) = 1 F(n) = F(n-1) + F(n-2) for n > 1

  • Note base case

    • Definition can’t be completely self-referential

    • Must eventually come down to something that’s solved “directly”

I know the steps needed to write a simple recursive method in Java

  • Strongly Agree

  • Agree

  • Disagree

  • Strongly Disagree

Recursive Factorial

public static int factorial (int n) {

if (n == 1)

return 1;


return n * factorial(n-1);


  • Exercise: trace execution (show method calls) for n=5

Why Do Recursive Methods Work?

Activation Records on the Run-time Stack are the key:

  • Each time you call a function (any function) you get a new activation record.

  • Each activation record contains a copy of all local variables and parameters for that invocation.

  • The activation record remains on the stack until the function returns, then it is destroyed.

    Try yourself: use your IDE’s debugger and put a breakpoint in the recursive algorithm

    Look at the call-stack.

Broken Recursive Factorial

public static int Brokenfactorial(int n){

int x = Brokenfactorial(n-1);

if (n == 1)

return 1;


return n * x;


  • What’s wrong here? Trace calls “by hand”

    • BrFact(2) -> BrFact(1) -> BrFact(0) -> BrFact(-1) -> BrFact(-2) -> …

    • Problem: we do the recursive call first before checking for the base case

    • Never stops! Like an infinite loop!

Recursive Design

Recursive methods/functions require:

1) One or more (non-recursive) base cases that will cause the recursion to end.

if (n == 1) return 1;

2) One or more recursive cases that operate on smaller problems and get you closer to the base case.

return n * factorial(n-1);

Note: The base case(s) should always be checked before the recursive call.

Rules for Recursive Algorithms

  • Base case - must have a way to end the recursion

  • Recursive call - must change at least one of the parameters and make progress towards the base case

    • exponentiation (x,y)

      • base: if y is 0 then return 1

      • recursive: else return (multiply x times exponentiation(x,y-1))

How to Think/Design with Recursion

  • Many people have a hard time writing recursive algorithms

  • The key: focus only at the current “stage” of the recursion

    • Handle the base case, then…

    • Decide what recursive-calls need to be made

      • Assume they work (as if by magic)

    • Determine how to use these calls’ results

Example: List Processing

  • Is an item in a list? First, get a reference current to the first node

    • (Base case) If current is null, return false

    • (Base case #2) If the first item equals the target, return true

    • (Recursive case – might be on the remainder of the list)

      • current =

      • return result of recursive call on new current

Next: Trees and Grammars

  • Lab on binary tree data structures

  • Maybe: HW5 on grammars

  • Lecture Later: Recursion vs. iteration

    • Which to choose?

    • Does it matter?

  • Maybe Later: recursion as an design strategy

Next: Time Complexity and Recursion

  • Recursion vs. iteration

    • Which to choose?

    • Does it matter?

  • Later: recursion as an design strategy

Recursion vs. Iteration

Interesting fact: Any recursive algorithm can be re-written as an iterative algorithm (loops)

  • Not all programming languages support recursion: COBOL, early FORTRAN.

  • Some programming languages rely on recursion heavily: LISP, Prolog, Scheme.

To Recurse or Not To Recurse?

  • Recursive solutions often seem elegant

  • Sometimes recursion is an efficient design strategy

  • But sometimes it’s definitely not

    • Important! we can define recursively and implement non-recursively

    • Many recursive algorithms can be re-written non-recursively

      • Use an explicit stack

      • Remove tail-recursion (compilers often do this for you)

To Recurse or Not to Recurse?

  • Sorting

    • Selection sort vs. mergesort – which to choose?

  • Factorial

    • Could just write a loop.

    • Any advantage to the recursive version?

  • Binary search

    • We’ll see two versions. Which to choose?

  • Fibonacci

    • Let’s consider Fibonacci carefully…

Recursive Fibonacci method

  • This is elegant code, no?long fib(int n) { if ( n == 0 ) return 1; if ( n == 1 ) return 1; return fib(n-1) + fib(n-2);}

  • Let’s start to trace it for fib(6)

Trace of fib(5)

  • For fib(5), we call fib(4) and fib(3)

    • For fib(4), we call fib(3) and fib(2)

      • For fib(3), we call fib(2) and fib(1)

        • For fib(2), we call fib(1) and fib(0). Base cases!

        • fib(1). Base case!

      • For fib(2), we call fib(1) and fib(0). Base cases!

    • For fib(3), we call fib(2) and fib(1)

      • For fib(2), we call fib(1) and fib(0). Base cases!

      • fib(1). Base case!

Fibonacci: recursion is a bad choice

  • Note that subproblems (like fib(2) ) repeat, and solved again and again

    • We don’t remember that we’ve solved one of our subproblems before

    • For this problem, better to store partial solutions instead of recalculating values repeatedly

    • Turns out to have exponential time-complexity!

Non-recursive Fibonacci

  • Two bottom-up iterative solutions:

    • Create an array of size n, and fill with values starting from 1 and going up to n

    • Or, have a loop from small values going up, but

      • only remember two previous Fibonacci values

      • use them to compute the next one

      • (See next slide)

Iterative Fibonacci

long fib(int n) {

if ( n < 2 ) return 1; long answer; long prevFib=1, prev2Fib=1; // fib(0) & fib(1) for (int k = 2; k <= n; ++k) {

answer = prevFib + prev2Fib;

prev2Fib = prevFib;

prevFib = answer;


return answer;


Next: Putting Recursion to Work

  • Divide and Conquer design strategy

    • Its form

    • Examples:

      • Binary Search

      • Merge Sort

    • Time complexity issues

Divide and Conquer

  • It is often easier to solve several small instances of a problem than one large one.

    • divide the problem into smaller instances of the same problem

    • solve (conquer) the smaller instances recursively

    • combine the solutions to obtain the solution for original input

    • Must be able to solve one or more small inputs directly

  • This is an algorithm design strategy

    • Computer scientists learn many more of these

General Strategy for Div. & Conq.

Solve (an input I)

n = size(I)

if (n <= smallsize)

solution = directlySolve(I);


divide I into I1, …, Ik.

for each i in {1, …, k}

Si = solve(Ii);

solution = combine(S1, …, Sk);

return solution;

Why Divide and Conquer?

  • Sometimes it’s the simplest approach

  • Divide and Conquer is often more efficient than “obvious” approaches

    • E.g. BinarySearch vs. Sequential Search

    • E.g. Mergesort, Quicksort vs. SelectionSort

  • But, not necessarily efficient

    • Might be the same or worse than another approach

  • We must analyze each algorithm's time complexity

  • Note: divide and conquer may or may not be implemented recursively

Top-Down Strategy

  • Divide and Conquer algorithms illustrate a top-down strategy

    • Given a large problem, identify and break into smaller subproblems

    • Solve those, and combine results

  • Most recursive algorithms work this way

  • The alternative? Bottom-up

    • Identify and solve smallest subproblems first

    • Combine to get larger solutions until solve entire problem




Binary Search of a Sorted Array

  • Strategy

    • Find the midpoint of the array

    • Is target equal to the item at midpoint?

    • If smaller, look in the first half

    • If larger, look in second half

Binary Search (non-recursive)

int binSearch ( array[], target) {

int first = 0; int last = array.length-1;

while ( first <= last ) {

mid = (first + last) / 2;

if ( target == array[mid] ) return mid; // found it

else if ( target < array[mid] ) // must be in 1st half

last = mid -1;

else // must be in 2nd half

first = mid + 1


return -1; // only got here if not found above


Binary Search (recursive)

int binSearch ( array[], first, last, target) {

if ( first <= last ) {

mid = (first + last) / 2;

if ( target == array[mid] ) // found it!

return mid;

else if ( target < array[mid] ) // must be in 1st half

return binSearch( array, first, mid-1, target);

else // must be in 2nd half

return binSearch(array, mid+1, last, target);


return -1;


  • No loop! Recursive calls takes its place

    • But don’t think about that if it confuses you!

  • Base cases checked first? (Why? Zero items? One item?)

Mergesort is Classic Divide & Conquer

Algorithm: Mergesort

  • Specification:

    • Input: Array E and indexes first, and Last, such that the elements E[i] are defined for first <= i <= last.

    • Output: E[first], …, E[last] is sorted rearrangement of the same elements

  • Algorithm:

    void mergeSort(Element[] E, int first, int last){

    if (first < last) {

    int mid = (first+last)/2;

    mergeSort(E, first, mid);

    mergeSort(E, mid+1, last);

    merge(E, first, mid, last); // merge 2 sorted halves



Exercise: Trace Mergesort Execution

  • Can you trace MergeSort() on this list?A = {8, 3, 2, 9, 7, 1, 5, 4};

Efficiency of Mergesort

  • Wait for CS2150 and CS4102 to study efficiency of this and other recursive algorithms

  • But…

    • It is more efficient that other sorts likeSelection Sort, Bubble Sort, Insertion Sort

    • It’s O(n lg n) which is the same order-class as the most efficient sorts (also quicksort and heapsort)

  • The point is that the D&C approach matters here, and a recursive definition and implementation is a “win”

Merging Sorted Sequences

  • Problem:

    • Given two sequences A and B sorted in non-decreasing order, merge them to create one sorted sequence C

    • Input size: C has n items, and A and B have n/2

  • Strategy:

    • Determine the first item in C: it should be the smaller of the first item in A and the first in B.

    • Suppose it is the first item of A. Copy that to C.

    • Then continue merging B with “rest of A” (without the item copied to C). Repeat!

Algorithm: Merge

merge(A, B, C)

if (A is empty)

append what’s left in B to C

else if (B is empty)

append what’s left in A to C

else if (first item in A <= first item in B)

append first item in A to C

merge (rest of A, B, C)

else // first item in B is smaller

append first item in B to C

merge (A, rest of B, C)


Summary of Recursion Concepts

  • Recursion is a natural way to solve many problems

    • Sometimes it’s a clever way to solve a problem that is not clearly recursive

  • Sometimes recursion produces an efficient solution (e.g. mergesort)

    • Sometimes it doesn’t (e.g. fibonacci)

  • To use recursion or not is a design decision for your “toolbox”

Recursion: Design and Implementation

  • “The Rules”

    • Identify one or more base (simple) cases that can be solved without recursion

      • In your code, handle these first!!!

    • Determine what recursive call(s) are needed for which subproblems

    • Also, how to use results to solve the larger problem

    • Hint: At this step, don’t think about how recursive calls process smaller inputs! Just assume they work!

Exercise: Find Max and Min

  • Given a list of elements, find both the maximum element and the minimum element

  • Obvious solution:

    • Consider first element to be max

    • Consider first element to be min

    • Scan linearly from 2nd to last, and update if something larger then max or if something smaller than min

  • Class exercise:

    • Write a recursive function that solves this using divide and conquer.

      • Prototype: void maxmin (list, first, last, max, min);

      • Base case(s)? Subproblems? How to combine results?

What’s Next?

  • Recursive Data Structures

    • Binary trees

      • Representation

      • Recursive algorithms

    • Binary Search Trees

      • Binary Trees with constraints

  • Parallel Programming using Threads

  • Login