Recursive Thinking
The Factorial Function n!= n(n-1)(n-2)…. 3 2 1 The standard Factorial Function written without recursion is provided below: // The Non-Recursive Factorial Function public static int simpleFactorial( int n ) { if (n < 0) return 0; // Make sure n >= 0 int product = 1; // “Base Case” Product is one. for (int k = 1; k < n; k ++) product *= k; return product; }
The Factorial Function n!= n(n-1)(n-2)…. 3 2 1 n!= n (n-1)! Can break a difficult problem ( n! ) into a smaller, more manageable problem of a similar structure ( (n-1)! is now easier than calculating n!) (n-1)!
What Is Recursion? It is a problem-solving process Breaks a problem into identical but smaller problems Eventually you reach a smallest problem Answer is obvious or trivial Using that solution enables you to solve the previous problems Eventually the original problem is solved
Recursive Factorial Function // A Recursive Factorial Function public static int factorial( int n ) { if (n < 0) return 0; // Make sure n >= 0 if (n == 0 || n == 1) return 1; // Base Cases return ( n * factorial (n-1) ); // Recursive Call } Conclusion: recursion splits a problem Into one or more simpler versions of itself
Is it possible to solve any problem recursively?
Requirements for Recursive Solution At least one “small” case that you can solve directly (base case) A way of breaking a larger problem down into: One or more smaller sub-problems Each of the same kind as the original A way of combining sub-problem results into an overall solution to the larger problem
Writing a Recursive Method Method definition must provide parameter Leads to different cases Typically includes an if or a switch statement One or more of these cases should provide a non recursive solution The base or stopping case One or more cases includes recursive call Takes a step towards the base case
Recursive Design Example Write a recursive algorithm for finding length of a string ‘H’ ‘e’ ‘l’ ‘l’ ‘o’ ‘\0’
Recursive algorithm for finding the length of a string if string is empty (no characters) return 0 base case else recursive case compute length of string without first character return 1 + that length
Recursive algorithm for finding length of a string public static int length (String str) { if (str == null || str.equals(“”)) return 0; else return length(str.substring(1)) + 1; }
Recursive algorithm for finding length of a string Overall result length(“ace”) 3 return 1 + length(“ce”) 2 return 1 + length(“e”) 1 return 1 + length(“”)
Simple recursive example void test(int i) { if (i > 1) test(i / 2); } System.out.print("*"); How many asterisks are printed by the method call test(5)?
Carrano, Data Structures and Abstractions with Java, Second Edition Towers of Hanoi The initial configuration of the Towers of Hanoi for three disks Carrano, Data Structures and Abstractions with Java, Second Edition
Carrano, Data Structures and Abstractions with Java, Second Edition Towers of Hanoi Rules for the Towers of Hanoi game Move one disk at a time. Each disk you move must be a topmost disk. No disk may rest on top of a disk smaller than itself. You can store disks on the second pole temporarily, as long as you observe the previous two rules. Carrano, Data Structures and Abstractions with Java, Second Edition
Carrano, Data Structures and Abstractions with Java, Second Edition Towers of Hanoi The sequence of moves for solving the Towers of Hanoi problem with three disks. Carrano, Data Structures and Abstractions with Java, Second Edition
Carrano, Data Structures and Abstractions with Java, Second Edition Towers of Hanoi The smaller problems in a recursive solution for four disks Carrano, Data Structures and Abstractions with Java, Second Edition
Towers of Hanoi Algorithm solveTowers (numberOfDisks, startPole, tempPole, endPole) if (numberOfDisks == 1) Move disk from startPole to endPole else { solveTowers (numberOfDisks - 1, startPole, endPole, tempPole) solveTowers (numberOfDisks - 1, tempPole, startPole, endPole) } The smaller problems in a recursive solution for four disks Carrano, Data Structures and Abstractions with Java, Second Edition
Debugging a recursive method If a recursive method does not work, check the following: Does the method have at least one input value? Does the method contain a statement that tests an input value and leads to different cases? Did you consider all possible cases? Does at least one of these cases cause at least one recursive call? Does these recursive calls get closer to the base case? Did you consider a base case? Carrano, Data Structures and Abstractions with Java, Second Edition
How to prove the correctness of a recursive algorithm?
Correctness of a recursive algorithm From Algorithm theory: an algorithm is correct if it satisfies the following TWO conditions: Produces correct results for all valid inputs Always terminates
Proof by Induction Prove the theorem for the base case(s): n=0 Show that: If the theorem is assumed true for n, Then it must be true for n+1 Result: Theorem true for all n ≥ 0.
Correctness of a recursive algorithm Recursive proof is similar to induction: Show base case recognized and solved correctly Show that If all smaller problems are solved correctly, Then original problem is also solved correctly Show that each recursive case makes progress towards the base case termination properly
Pros and Cons of recursive methods Recursive code is often simpler than iterative (easier to write, read, and debug) Slower than iterative