Recursion Aaron Tan tantc/cs1101.html.

84
Recursion Aaron Tan http://www.comp.nus.edu.sg/~tantc/ cs1101.html

Transcript of Recursion Aaron Tan tantc/cs1101.html.

Page 1: Recursion Aaron Tan tantc/cs1101.html.

Recursion

Aaron Tan

http://www.comp.nus.edu.sg/~tantc/cs1101.html

Page 2: Recursion Aaron Tan tantc/cs1101.html.

2Recursion

Recursion

+

Page 3: Recursion Aaron Tan tantc/cs1101.html.

3Recursion

What is Recursion? (1/2) To perform a task T by performing some similar smaller

task(s) T’.

Example:

Formula for factorial:

n! = n * (n-1) * (n-2) * … * 2 * 1 for n > 0

0! = 1

Recursive formula for factorial:

n! = n * (n–1)! for n>0

0! = 1

(Examples: 3! = 6; 4! = 24; 7! = 5040)

Page 4: Recursion Aaron Tan tantc/cs1101.html.

4Recursion

What is Recursion? (2/2) The idea behind recursion is similar to PMI (Principle of

Mathematical Induction).

Example: Prove the recursive formula for factorial.

Basis: 0! = 1

Induction hypothesis: Assume that the recursive formula is true for x > 0.

Inductive step:

(x + 1)! = (x + 1) * x * (x – 1) * … * 1

= (x + 1) * x!

Page 5: Recursion Aaron Tan tantc/cs1101.html.

5Recursion

Recursive Definitions A definition that defines something in terms of itself is

called a recursive definition.

The descendants of a person are the person’s children and all of the descendants of the person’s children.

A list of numbers is a number or a number followed by a comma and a list of numbers.

A recursive algorithm is an algorithm that invokes itself to solve smaller or simpler instances of a problem instances.

The factorial of a number n is: n times the factorial of n-1.

Page 6: Recursion Aaron Tan tantc/cs1101.html.

6Recursion

How to Multiply 6 by 3? (1/5) Assume that we know only addition but not multiplication,

except for the simplest case of x * 1 = x.

To employ recursion, we solve our problem by solving a smaller (but similar) problem, and then use the solution of this smaller problem to derive the solution of the original problem.

Page 7: Recursion Aaron Tan tantc/cs1101.html.

7Recursion

How to Multiply 6 by 3? (2/5) To solve ‘multiply 6 by 3’:

1. Solve smaller problem: Multiply 6 by 2.

2. Connect the solution of the smaller problem with the solution of the original problem: Add 6 to the result of (1).

Apply the same technique to solve ‘multiply 6 by 2’:

1.1. Solve smaller problem: Multiply 6 by 1.

1.2. Connect the solution of the smaller problem with the solution of the original problem: Add 6 to the result of (1.1).

Page 8: Recursion Aaron Tan tantc/cs1101.html.

8Recursion

How to Multiply 6 by 3? (3/5) To solve ‘multiply 6 by 1’:

Do not need to solve smaller problem as the problem can be solved directly. Answer: 6 * 1 = 6.

We then reconstruct the solution

‘Multiply 6 by 1’ is 6.

‘Multiply 6 by 2’ is 6 + the solution of ‘multiply 6 by 1’, or 12.

‘Multiply 6 by 3’ is 6 + the solution of ‘multiply 6 by 2’, or 18.

Page 9: Recursion Aaron Tan tantc/cs1101.html.

9Recursion

How to Multiply 6 by 3? (4/5)// recursive method to compute// m * n, where n is positive public static int multiply (int m, int n) { int ans;

if (n==1) ans = m; // simple case else ans = m + multiply(m, n-1);

return ans;}

public static int multiply (int m, int n) { if (n==1) return m; else return m + multiply(m, n-1); }

or

Page 10: Recursion Aaron Tan tantc/cs1101.html.

10Recursion

How to Multiply 6 by 3? (5/5)// iterative method to compute// m * n, where n is positive public static int multiply (int m, int n) { int ans = 0; for (int i = 1; i <= n; ++i) ans += m; return ans;}

public static int multiply (int m, int n) { int ans = 0; while (n-- > 0) ans += n; return ans;}

or

Page 11: Recursion Aaron Tan tantc/cs1101.html.

11Recursion

Count Occurrences of Character (1/4)

Mississippi sassafras

We want

countChar('s', "Mississippi sassafras")

to return the value of 8.

Recursive thinking goes...

If I could just get someone to count the s’s in this smaller string…

… then the number of s’s is either that number or 1 more, depending on whether the first letter is an s.

Page 12: Recursion Aaron Tan tantc/cs1101.html.

12Recursion

Count Occurrences of Character (2/4)

// count the number of occurrences // of character ch in string str. public static int countChar(char ch, String str) { int ans;

if (str.length() == 0) // base case ans = 0; else if (str.charAt(0) == ch) ans = 1 + countChar(ch, str.substring(1)); else ans = countChar(ch, str.substring(1)); return ans;}

Page 13: Recursion Aaron Tan tantc/cs1101.html.

13Recursion

Count Occurrences of Character (3/4)

public static int countChar(char ch, String str) {

if (str.length() == 0) // base case return 0; else if (str.charAt(0) == ch) return 1 + countChar(ch, str.substring(1)); else return countChar(ch, str.substring(1));}

or

Page 14: Recursion Aaron Tan tantc/cs1101.html.

14Recursion

Count Occurrences of Character (4/4)

public static int countChar(char ch, String str) { int ans = 0;

for (int i = 0; i < str.length(); ++i) { if (str.charAt(i) == ch) ++ans; }

return ans;}

Compare with iterative version:

Page 15: Recursion Aaron Tan tantc/cs1101.html.

15Recursion

Factorial: Definition An imprecise definition

A precise definition

11)1(

01!

nnn

nn

1)!1(

01!

nnn

nn

Ellipsis tells the reader to use intuition to recognise the pattern.

Page 16: Recursion Aaron Tan tantc/cs1101.html.

16Recursion

Recursive Methods A recursive method generally has two parts.

A termination part that stops the recursion. This is called the base case (or anchor case). The base case should have a simple or trivial solution.

One or more recursive calls. This is called the recursive case. The recursive case calls the same method but with simpler or

smaller arguments.

if ( base case satisfied ) {return value;

}else {

make simpler recursive call(s);}

Page 17: Recursion Aaron Tan tantc/cs1101.html.

17Recursion

factorial() (1/2)

public static int factorial(n) { if (n == 0) return 1; else return n * factorial(n-1);}

Base case.

Recursive case deals with a simpler (smaller) version of the same task.

Page 18: Recursion Aaron Tan tantc/cs1101.html.

18Recursion

factorial() (2/2)public static int factorial(n) { if (n == 0) return 1; else return n * factorial(n-1);}

public static void main(String[] args) { Scanner scanner = new Scanner(System.in);

int number = scanner.nextInt(); int nfactorial = factorial(number);

System.out.println(number + "! = " + nfactorial);}

Page 19: Recursion Aaron Tan tantc/cs1101.html.

19Recursion

Factorial: Recursive Invocation A new activation record is created for every method

invocation Including recursive invocations

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return n * factorial(n-1);

n = 1factorial() return n * factorial(n-1);

n = 0factorial() return 1;

Page 20: Recursion Aaron Tan tantc/cs1101.html.

20Recursion

Factorial: Result Passing (1/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return n * factorial(n-1);

n = 1factorial() return n * factorial(n-1);

n = 0factorial() return 1;

Page 21: Recursion Aaron Tan tantc/cs1101.html.

21Recursion

Factorial: Result Passing (2/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return n * factorial(n-1);

n = 1factorial() return n * factorial(n-1);

n = 0factorial() return 1;

Page 22: Recursion Aaron Tan tantc/cs1101.html.

22Recursion

Factorial: Result Passing (3/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return n * factorial(n-1);

n = 1factorial() return n * 1;

Page 23: Recursion Aaron Tan tantc/cs1101.html.

23Recursion

Factorial: Result Passing (4/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return n * factorial(n-1);

n = 1factorial() return 1 * 1;

Page 24: Recursion Aaron Tan tantc/cs1101.html.

24Recursion

Factorial: Result Passing (5/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return n * factorial(n-1);

n = 1factorial() return 1 * 1;

Page 25: Recursion Aaron Tan tantc/cs1101.html.

25Recursion

Factorial: Result Passing (6/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return n * 1;

Page 26: Recursion Aaron Tan tantc/cs1101.html.

26Recursion

Factorial: Result Passing (7/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return 2 * 1;

Page 27: Recursion Aaron Tan tantc/cs1101.html.

27Recursion

Factorial: Result Passing (8/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * factorial(n-1);

n = 2factorial() return 2 * 1;

Page 28: Recursion Aaron Tan tantc/cs1101.html.

28Recursion

Factorial: Result Passing (9/12)

main() int nfactorial = factorial(n);

n = 3factorial() return n * 2;

Page 29: Recursion Aaron Tan tantc/cs1101.html.

29Recursion

Factorial: Result Passing (10/12)

main() int nfactorial = factorial(n);

n = 3factorial() return 3 * 2;

Page 30: Recursion Aaron Tan tantc/cs1101.html.

30Recursion

Factorial: Result Passing (11/12)

main() int nfactorial = factorial(n);

n = 3factorial() return 3 * 2;

Page 31: Recursion Aaron Tan tantc/cs1101.html.

31Recursion

Factorial: Result Passing (12/12)

main() int nfactorial = 6;

Page 32: Recursion Aaron Tan tantc/cs1101.html.

32Recursion

Infinite Recursion A common programming error when using recursion is

to not stop making recursive calls. The program will continue to recurse until it runs out of

memory. Be sure that your recursive calls are made with simpler or

smaller subproblems, and that your algorithm has a base case that terminates the recursion.

Avoid redundant base case:

public static int factorial(n) { if (n == 0) return 1; else if (n == 1) return 1; else return n * factorial(n-1);}

Page 33: Recursion Aaron Tan tantc/cs1101.html.

33Recursion

Computing Sum of Squares (1/5)

Given 2 positive integers m and n, where m ≤ n, compute:

sumSquares(m, n) = m2 + (m+1)2 + … + n2

Example:

sumSquares(5, 10) = 52 + 62 + 72 + 82 + 92 + 102 = 355

Page 34: Recursion Aaron Tan tantc/cs1101.html.

34Recursion

Computing Sum of Squares (2/5) ‘Going-up’ recursion:

‘Going-down’ recursion:

public static int sumSquares (int m, int n){ if (m == n) return m * m; else return m*m + sumSquares(m+1, n);}

public static int sumSquares (int m, int n){ if (m == n) return n * n; else return n*n + sumSquares(m, n-1);}

Page 35: Recursion Aaron Tan tantc/cs1101.html.

35Recursion

Computing Sum of Squares (3/5) ‘Combining two half-solutions’ recursion:

public static int sumSquares (int m, int n){ if (m == n) return m * m; else { int middle = (m + n)/2; return sumSquares(m, middle) + sumSquares(middle+1, n); }}

Page 36: Recursion Aaron Tan tantc/cs1101.html.

36Recursion

Computing Sum of Squares (4/5) Call trees for ‘going-up’ and ‘going-down’ versions.

sumSquares(5,10)

sumSquares(6,10)

sumSquares(7,10)

sumSquares(8,10)

sumSquares(9,10)

sumSquares(10,10)

100

100+81

181+64

245+49

294+36

330+25

355

sumSquares(5,10)

sumSquares(5,9)

sumSquares(5,8)

sumSquares(5,7)

sumSquares(5,6)

sumSquares(5,5)

25

25+36

61+49

110+64

174+81

255+100

355

Page 37: Recursion Aaron Tan tantc/cs1101.html.

37Recursion

Computing Sum of Squares (5/5) Call tree for ‘combining two half-solutions’ version.

sumSquares(5,10)

sumSquares(8,10)

sumSq(5,6)

25

245

355

sumSquares(5,7)

sumSq(7,7) sumSq(8,9) sumSq(10,10)

sumSq(5,5) sumSq(6,6)

36

25 36

61

49

49

110

64

sumSq(8,8) sumSq(9,9)

81

64 81

145 100

100

Page 38: Recursion Aaron Tan tantc/cs1101.html.

38Recursion

Computing GCD (1/7) Greatest common divisor (GCD) of two non-negative

integers (not both zero).

1 if)%,(

0 if),(

nnmnGCD

nmnmGCD

+

Page 39: Recursion Aaron Tan tantc/cs1101.html.

39Recursion

Computing GCD (2/7) Trace gcd(539, 84)

gcd(539, 84)

gcd(84, 35)

gcd(35, 14)

gcd(14, 7)

gcd(7, 0)

public static int gcd(int m, int n) {if (n == 0) return m;else return gcd(n, m % n);

}

Page 40: Recursion Aaron Tan tantc/cs1101.html.

40Recursion

Computing GCD (3/7) Trace gcd(539, 84) public static int gcd(int m, int n) {

if (n == 0) return m;else return gcd(n, m % n);

}gcd(539, 84)

gcd(84, 35)

gcd(35, 14)

gcd(14, 7)

gcd(7, 0)

7

Page 41: Recursion Aaron Tan tantc/cs1101.html.

41Recursion

Computing GCD (4/7) Trace gcd(539, 84) public static int gcd(int m, int n) {

if (n == 0) return m;else return gcd(n, m % n);

}gcd(539, 84)

gcd(84, 35)

gcd(35, 14)

gcd(14, 7)

7

Page 42: Recursion Aaron Tan tantc/cs1101.html.

42Recursion

Computing GCD (5/7) Trace gcd(539, 84) public static int gcd(int m, int n) {

if (n == 0) return m;else return gcd(n, m % n);

}gcd(539, 84)

gcd(84, 35)

gcd(35, 14)

7

Page 43: Recursion Aaron Tan tantc/cs1101.html.

43Recursion

Computing GCD (6/7) Trace gcd(539, 84) public static int gcd(int m, int n) {

if (n == 0) return m;else return gcd(n, m % n);

}gcd(539, 84)

gcd(84, 35)

7

Page 44: Recursion Aaron Tan tantc/cs1101.html.

44Recursion

Computing GCD (7/7) Trace gcd(539, 84) public static int gcd(int m, int n) {

if (n == 0) return m;else return gcd(n, m % n);

}gcd(539, 84) 7

Page 45: Recursion Aaron Tan tantc/cs1101.html.

45Recursion

Fibonacci Numbers (1/5) Developed by Leonardo Pisano in 1202.

Investigating how fast rabbits could breed under idealized circumstances.

Assumptions

A pair of male and female rabbits always breed and produce another pair of male and female rabbits.

A rabbit becomes sexually mature after one month, and that the gestation period is also one month.

Pisano wanted to know the answer to the question how many rabbits would there be after one year?

Page 46: Recursion Aaron Tan tantc/cs1101.html.

46Recursion

Fibonacci Numbers (2/5) The sequence generated is:

1, 1, 2, 3, 5, 8, 13, 21, 34, …

Some version starts with 0: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

The number of pairs for a month is the sum of the number of pairs in the two previous months.

Page 47: Recursion Aaron Tan tantc/cs1101.html.

47Recursion

Fibonacci Numbers (3/5) What is the equation for Fibonacci sequence?

+

Page 48: Recursion Aaron Tan tantc/cs1101.html.

48Recursion

Fibonacci Numbers (4/5)// Version 1: 0, 1, 1, 2, 3, 5, 8, 13, 21, ...public static int fibonacci (int n) {if (n <= 1)

return n;else

return fibonacci(n-1) + fibonacci(n-2);}

// Version 2: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...public static int fibonacci (int n) {if (n <= 2)

return 1;else

return fibonacci(n-1) + fibonacci(n-2);}

Page 49: Recursion Aaron Tan tantc/cs1101.html.

49Recursion

Fibonacci Numbers (5/5)

Fibonacci(5)

Fibonacci(4) Fibonacci(3)

Fibonacci(2)Fibonacci(3) Fibonacci(2) Fibonacci(1)

Fibonacci(2) Fibonacci(1)

3 2

2 1

1 1

1 1

5

Page 50: Recursion Aaron Tan tantc/cs1101.html.

50Recursion

Tracing Recursive Codes (1/2) Beginners usually rely on tracing to understand the

sequence of recursive calls and the passing back of results.

Tail recursion is one in which the recursive call is the last operation in the code.

Examples encountered that are tail-recursive: factorial, sum of squares (‘going-up’ and ‘going-down’ versions), GCD.

Examples that are not tail-recursive: sum of squares (‘combining two half-solutions’ version), Fibonacci sequence.

However, tracing a recursive code is tedious, especially for non-tail-recursive codes. The call tree could be huge (example: Fibonacci.)

Page 51: Recursion Aaron Tan tantc/cs1101.html.

51Recursion

Tracing Recursive Codes (2/2) If tracing is needed to aid understanding, start tracing with

small problem sizes, then gradually see the relationship between the successive calls.

Students should grow out of tracing and understand recursion by examining the relationship between the problem and its immediate subproblem(s).

Page 52: Recursion Aaron Tan tantc/cs1101.html.

52Recursion

Notes It is not typical to write a recursive main() method. Besides direct recursion, there could be mutual or indirect

recursion Examples: Method A calls method B, which calls method A.

Method X calls method Y, which calls method Z, which calls method X.

Sometimes, auxiliary subroutines are needed to implement recursion.

The inherent nature of recursion gives rise to a ‘loop’ structure. At this point, most problem can be solved with such simple recursion. Recursion in a loop (or nested loops) is only needed for more advanced problems.

Page 53: Recursion Aaron Tan tantc/cs1101.html.

53Recursion

Recursion versus Iteration (1/2) Iteration can be more efficient

Replaces method calls with looping Less memory is used (no activation record for each call)

Some good compilers are able to transform a tail-recursion code into an iterative code.

If a problem can be done easily with iteration, then do it with iteration. For example, Fibonacci can be coded with iteration or recursion,

but the recursive version is very inefficient (large call tree), so use iteration instead. (Can you write an iterative version for Fibonacci?)

Additional technique (such as memoization) could be used to improve efficiency – covered in advance course.

Page 54: Recursion Aaron Tan tantc/cs1101.html.

54Recursion

Recursion versus Iteration (2/2) Many problems are more naturally solved with recursion,

which can provide elegant solution. Towers of Hanoi Mergesort

Conclusion: choice depends on problem and the solution context. In general, use recursion if A recursive solution is natural and easy to understand. A recursive soluition does not result in excessive duplicate

computation. The equivalent iterative solution is too complex.

Page 55: Recursion Aaron Tan tantc/cs1101.html.

55Recursion

Towers of Hanoi (1/12) This classical “Towers of Hanoi” puzzle has attracted the

attention of computer scientists more than any other puzzles.

Invented by Edouard Lucas, a French mathematician, in1883.

There are 3 poles (A, B and C) and a tower of disks on the first pole A, with the smallest disk on the top and the biggest at the bottom. The purpose of the puzzle is to move the whole tower from pole A to pole C, with the following simple rules: Only one disk can be moved at a time. A bigger disk must not rest on a smaller disk.

Page 56: Recursion Aaron Tan tantc/cs1101.html.

56Recursion

Towers of Hanoi (2/12) Legend:

In the great temple of Brahma in Benares, on a brass plate under the dome that marks the center of the world, there are 64 disks of pure gold that the priests carry one at a time between these diamond needles according to Brahma's immutable law: No disk may be placed on a smaller disk. In the begging of the world all 64 disks formed the Tower of Brahma on one needle. Now, however, the process of transfer of the tower from one needle to another is in mid course. When the last disk is finally in place, once again forming the Tower of Brahma but on a different needle, then will come the end of the world and all will turn to dust.

Reference: R. Douglas Hofstadter. Metamagical themas. Scientific American, 248(2):16-22, March 1983.

Demo: Tower of Hanoi

Page 57: Recursion Aaron Tan tantc/cs1101.html.

57Recursion

Towers of Hanoi (3/12) We attempt to write a produce to produce instructions on

how to move the disks from pole A to pole C to complete the puzzle.

Example: A tower with 3 disks. Output produced by program is as followed. It is assumed

that only the top disk can be moved.Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

Page 58: Recursion Aaron Tan tantc/cs1101.html.

58Recursion

Towers of Hanoi (4/12) Example: A tower with 3 disks.

Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

A B C

Page 59: Recursion Aaron Tan tantc/cs1101.html.

59Recursion

Towers of Hanoi (5/12) Example: A tower with 3 disks.

Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

A B C

Page 60: Recursion Aaron Tan tantc/cs1101.html.

60Recursion

Towers of Hanoi (6/12) Example: A tower with 3 disks.

Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

A B C

Page 61: Recursion Aaron Tan tantc/cs1101.html.

61Recursion

Towers of Hanoi (7/12) Example: A tower with 3 disks.

Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

A B C

Page 62: Recursion Aaron Tan tantc/cs1101.html.

62Recursion

Towers of Hanoi (8/12) Example: A tower with 3 disks.

Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

A B C

Page 63: Recursion Aaron Tan tantc/cs1101.html.

63Recursion

Towers of Hanoi (9/12) Example: A tower with 3 disks.

Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

A B C

Page 64: Recursion Aaron Tan tantc/cs1101.html.

64Recursion

Towers of Hanoi (10/12) Example: A tower with 3 disks.

Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

A B C

Page 65: Recursion Aaron Tan tantc/cs1101.html.

65Recursion

Towers of Hanoi (11/12) Example: A tower with 3 disks.

Move disk from A to CMove disk from A to BMove disk from C to BMove disk from A to CMove disk from B to AMove disk from B to CMove disk from A to C

A B C

VIOLA!

Page 66: Recursion Aaron Tan tantc/cs1101.html.

66Recursion

Towers of Hanoi (12/12)

public static void main(String[] args) { Scanner scanner = new Scanner(System.in);

System.out.print( "Enter number of disks: " ); int disks = scanner.nextInt(); towers(disks, 'A', 'B', 'C');

}+

Page 67: Recursion Aaron Tan tantc/cs1101.html.

67Recursion

Binary Search (1/6) Compare the search value to the middle element of the

list. If the search value matches the middle element, the desired value has been located and the search is over.

If the search value doesn’t match, then if it is in the list it must be either to the left or right of the middle element.

The correct sublist can be searched using the same strategy – divide and conquer.

Page 68: Recursion Aaron Tan tantc/cs1101.html.

68Recursion

Binary Search (2/6)

data 3 6 128 17 20 3221 33 45

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

Compare search value to this element. If the search value matches, the search is successful. If the search value is less than this element (data[4]), then the search value, if it is in the list, must be to the left of data[4]. If the search value is greater than this element (data[4]), then if it is in the list, it must be to the right of data[4].

Page 69: Recursion Aaron Tan tantc/cs1101.html.

69Recursion

Binary Search (3/6) Example: Search for 20 in this list

data 3 6 128 17 20 3221 33 45

[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]

Go to middle of list. Compare this element with our search value. 17 is smaller than 20, so left half is ignored.

Go to middle of remaining list. Compare this element with our search value. Found!

Go to middle of remaining list. Compare this element with our search value. 32 is larger than 20, so right half is ignored.

Page 70: Recursion Aaron Tan tantc/cs1101.html.

70Recursion

Binary Search (4/6) Iterative version:

// binarySearch(): examine sorted list for a keypublic static int binarySearch(int[] data, int key) {

int left = 0; int right = data.length – 1; while (left <= right) { int mid = (left + right)/2; if (data[mid] == key)

return mid; else if (data[mid] < key) left = mid + 1; else right = mid – 1; } return -1;

}

Page 71: Recursion Aaron Tan tantc/cs1101.html.

71Recursion

Binary Search (5/6) Recursive version:

+

Page 72: Recursion Aaron Tan tantc/cs1101.html.

72Recursion

Binary Search (6/6) Calling the recursive binary search method.

public static void main(String[] args) { Scanner scanner = new Scanner(System.in);

int[] intArray = {3, 6, 8, 12, 17, 20, 21, 32, 33, 45}; System.out.print("Enter search key: ");

int searchKey = scanner.nextInt();

int index = binarysearch(intArray, searchKey, 0, intArray.length - 1);

System.out.println("Key found at index " + index);}

Page 73: Recursion Aaron Tan tantc/cs1101.html.

73Recursion

Efficiency of Binary Search Height of a binary tree is the worst case

number of comparisons needed to search a list.

Tree containing 31 nodes has a height of 5.

In general, a tree with n nodes has a height of log2(n+1).

Searching a list witha billion nodesonly requires 31comparisons.

Binary search isefficient!

Page 74: Recursion Aaron Tan tantc/cs1101.html.

74Recursion

Recursion on Data Structures Besides using recursion to compute numerical values

(factorial, Fibonacci numbers, etc.), recursion is also useful for processing on data structures (example: arrays).

Examples: Binary search on a sorted array. Finding maximum or minimum value in an array. Finding a path through the maze. And many others…

Some of the more complex problems belong to a more advanced course, but we shall look at some simpler problems.

Page 75: Recursion Aaron Tan tantc/cs1101.html.

75Recursion

Reversing an Array// reverse an integer array public static void reverse (int[] array, int start, int finish) { if (start < finish) { int temp = array[start]; array[start] = array[finish]; array[finish] = temp; reverse (array, start+1, finish-1); }}

public static void main(String[] args) { int[] intArray = { 3, 7, 1, 4, 12, 9, 7, 5 };

reverse (intArray, 0, intArray.length-1);}

Page 76: Recursion Aaron Tan tantc/cs1101.html.

76Recursion

Auxiliary Subroutines (1/3) Sometimes, for some reasons (say coupling), you may

be given a fixed signature of a method and asked to devise a recursive code for it. Example: Reverse a list

void reverse (int[] array)

Example: Binary search

void binarySearch (int[] data, int key)

In this case, you would need to write auxiliary method(s).

Page 77: Recursion Aaron Tan tantc/cs1101.html.

77Recursion

Auxiliary Subroutines (2/3) Reversing a list

// reverse an integer array public static void reverse (int[] array) { reverseAux (array, 0, array.length-1);}

// reverse an integer array private static void reverseAux (int[] array, int start, int finish) { if (start < finish) { int temp = array[start]; array[start] = array[finish]; array[finish] = temp; reverseAux (array, start+1, finish-1); }}

Page 78: Recursion Aaron Tan tantc/cs1101.html.

78Recursion

Auxiliary Subroutines (3/3) The call to reverse() method is then simplified as

follows. Note that this does not require the caller to provide the

starting and ending indices as in the previous version. This reduces coupling.

Note that the auxiliary method reverseAux() is declared as private, since it is only to be called by the reverse() method and not by any other methods.

Note also that the auxiliary method could also be named reverse(), since Java allows method overloading.

public static void main(String[] args) { int[] intArray = { 3, 7, 1, 4, 12, 9, 7, 5 };

reverse (intArray);}

Page 79: Recursion Aaron Tan tantc/cs1101.html.

79Recursion

Optional The following slides are for your reading. There are sorting algorithms that employ recursion:

quicksort, mergesort. These are faster sorting algorithms which will be covered in another module (CS1102).

Previous examples use simple recursion. The recursive call substitute the loop in the iterative counterpart.

The following examples (directory listing, anagrams) are slightly more complex, requiring the combination of a loop and recursive call.

Page 80: Recursion Aaron Tan tantc/cs1101.html.

80Recursion

Directory Listing List the names of all files in a given directory and its

subdirectories.

public void directoryListing(File dir) {

//assumption: dir represents a directoryString[] fileList = dir.list(); //get the contentsString dirPath = dir.getAbsolutePath();

for (int i = 0; i < fileList.length; i++) { File file = new File(dirPath + "/" + fileList[i]);

if (file.isFile()) { //it's a file System.out.println( file.getName() );

} else { directoryListing( file ); //it's a directory

} //so make a} //recursive call

}

Recursive caseRecursive case

End caseEnd case

TestTest

Page 81: Recursion Aaron Tan tantc/cs1101.html.

81Recursion

Anagram List all anagrams of a given word.

WordWord C A T

C T A

A T C

A C T

T C A

T A C

AnagramsAnagrams

Page 82: Recursion Aaron Tan tantc/cs1101.html.

82Recursion

Anagram Solution The basic idea is to make recursive calls on a sub-word

after every rotation. Here’s how:

CC AA TT RecursionRecursion

AA TT CC

TT CC AA

RecursionRecursion

RecursionRecursion

Rotate Left

Rotate Left

C A T

C T A

A T C

A C T

T C A

T A C

Page 83: Recursion Aaron Tan tantc/cs1101.html.

83Recursion

Anagram Method

End caseEnd case

TestTest

Recursive caseRecursive case

public void anagram( String prefix, String suffix ) {String newPrefix, newSuffix;int numOfChars = suffix.length();

if (numOfChars == 1) {//End case: print out one anagramSystem.out.println( prefix + suffix );

} else {for (int i = 1; i <= numOfChars; i++ ) {

newSuffix = suffix.substring(1, numOfChars);newPrefix = prefix + suffix.charAt(0);anagram( newPrefix, newSuffix );//recursive call//rotate left to create a rearranged suffixsuffix = newSuffix + suffix.charAt(0);

}}

}

Page 84: Recursion Aaron Tan tantc/cs1101.html.

84Recursion

End of file