42
1 Introduction to Recursion and Recursive Algorithms CS2110

1 Introduction to Recursion and Recursive Algorithms CS2110

Embed Size (px)

Citation preview

Page 1: 1 Introduction to Recursion and Recursive Algorithms CS2110

1

Introduction to Recursion and

Recursive Algorithms

CS2110

Page 2: 1 Introduction to Recursion and Recursive Algorithms CS2110

2

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

}

Page 3: 1 Introduction to Recursion and Recursive Algorithms CS2110

3

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

Page 4: 1 Introduction to Recursion and Recursive Algorithms CS2110

4

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

Page 5: 1 Introduction to Recursion and Recursive Algorithms CS2110

5

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)

Page 6: 1 Introduction to Recursion and Recursive Algorithms CS2110

6

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”

Page 7: 1 Introduction to Recursion and Recursive Algorithms CS2110

7

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

Java

1. Strongly Agree2. Agree3. Disagree4. Strongly

Disagree

Page 8: 1 Introduction to Recursion and Recursive Algorithms CS2110

8

Recursive Factorialpublic static int factorial (int n) {

if (n == 1)

return 1;

else

return n * factorial(n-1);

}

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

Page 9: 1 Introduction to Recursion and Recursive Algorithms CS2110

9

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 algorithmLook at the call-stack.

Page 10: 1 Introduction to Recursion and Recursive Algorithms CS2110

10

Broken Recursive Factorialpublic static int Brokenfactorial(int n){int x = Brokenfactorial(n-1);if (n == 1)

return 1;else

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!

Page 11: 1 Introduction to Recursion and Recursive Algorithms CS2110

11

Recursive DesignRecursive 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.

Page 12: 1 Introduction to Recursion and Recursive Algorithms CS2110

12

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))

Page 13: 1 Introduction to Recursion and Recursive Algorithms CS2110

13

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

Page 14: 1 Introduction to Recursion and Recursive Algorithms CS2110

14

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 = current.next• return result of recursive call on new current

Page 15: 1 Introduction to Recursion and Recursive Algorithms CS2110

15

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

Page 16: 1 Introduction to Recursion and Recursive Algorithms CS2110

16

Next: Time Complexity and Recursion

• Recursion vs. iteration– Which to choose?– Does it matter?

• Later: recursion as an design strategy

Page 17: 1 Introduction to Recursion and Recursive Algorithms CS2110

17

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.

Page 18: 1 Introduction to Recursion and Recursive Algorithms CS2110

18

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)

Page 19: 1 Introduction to Recursion and Recursive Algorithms CS2110

19

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…

Page 20: 1 Introduction to Recursion and Recursive Algorithms CS2110

20

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)

Page 21: 1 Introduction to Recursion and Recursive Algorithms CS2110

21

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!

Page 22: 1 Introduction to Recursion and Recursive Algorithms CS2110

22

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!

Page 23: 1 Introduction to Recursion and Recursive Algorithms CS2110

23

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)

Page 24: 1 Introduction to Recursion and Recursive Algorithms CS2110

24

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

Page 25: 1 Introduction to Recursion and Recursive Algorithms CS2110

25

Next: Putting Recursion to Work• Divide and Conquer design

strategy– Its form– Examples:

• Binary Search• Merge Sort

– Time complexity issues

Page 26: 1 Introduction to Recursion and Recursive Algorithms CS2110

26

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

Page 27: 1 Introduction to Recursion and Recursive Algorithms CS2110

27

General Strategy for Div. & Conq.

Solve (an input I)n = size(I)if (n <= smallsize)

solution = directlySolve(I);

elsedivide I into I1, …, Ik.for each i in {1, …, k}

Si = solve(Ii);

solution = combine(S1, …, Sk);

return solution;

Page 28: 1 Introduction to Recursion and Recursive Algorithms CS2110

28

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

Page 29: 1 Introduction to Recursion and Recursive Algorithms CS2110

29

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

Page 30: 1 Introduction to Recursion and Recursive Algorithms CS2110

30

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

first mid last

Page 31: 1 Introduction to Recursion and Recursive Algorithms CS2110

31

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 itelse if ( target < array[mid] ) // must be in 1st

halflast = mid -1;

else // must be in 2nd halffirst = mid + 1

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

}

Page 32: 1 Introduction to Recursion and Recursive Algorithms CS2110

32

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?)

Page 33: 1 Introduction to Recursion and Recursive Algorithms CS2110

33

Mergesort is Classic Divide & Conquer

Page 34: 1 Introduction to Recursion and Recursive Algorithms CS2110

34

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

}}

Page 35: 1 Introduction to Recursion and Recursive Algorithms CS2110

35

Exercise: Trace Mergesort Execution

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

Page 36: 1 Introduction to Recursion and Recursive Algorithms CS2110

36

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 like

Selection 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”

Page 37: 1 Introduction to Recursion and Recursive Algorithms CS2110

37

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!

Page 38: 1 Introduction to Recursion and Recursive Algorithms CS2110

38

Algorithm: Merge

merge(A, B, C)if (A is empty)

append what’s left in B to Celse if (B is empty)

append what’s left in A to Celse if (first item in A <= first item in B)

append first item in A to Cmerge (rest of A, B, C)

else // first item in B is smallerappend first item in B to Cmerge (A, rest of B, C)

return

Page 39: 1 Introduction to Recursion and Recursive Algorithms CS2110

39

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”

Page 40: 1 Introduction to Recursion and Recursive Algorithms CS2110

40

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!

Page 41: 1 Introduction to Recursion and Recursive Algorithms CS2110

41

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?

Page 42: 1 Introduction to Recursion and Recursive Algorithms CS2110

42

What’s Next?

• Recursive Data Structures– Binary trees

• Representation• Recursive algorithms

– Binary Search Trees• Binary Trees with constraints

• Parallel Programming using Threads