You are on page 1of 20

CSBP319- Data Structures

CIT, UAEU

1
Objectives
Understand the concept of recursion.
Know how to use recursive programming
techniques.
Have a better appreciation of recursion as a problem
solving technique.

COURSE OUTCOMES
Upon the successful completion of the course, students will be able to:
1. Apply recursion to solve problems.
2. Use APIs for implementing moderate size programs with data structures.
3. Design and implement linear data structures.
4. Design and implement tree data structures.
5. Model and Solve problems using graphs.
Outline

Introduction
Recursive Definition
Recursive String Methods
Recursive Array Processing
Tail Recursion
Recursion or Iteration
Introduction
Repeating instructions in a program can be
done in two ways
Iteratively
Recursively

Iterative methods use Loops to achieve


repetition of code
e.g for-loop, while loop, do-while etc
Defining Recursion
Recursion is the process of solving a problem by
reducing it into smaller versions of itself.

Recursive algorithm
Algorithm that finds the solution to a given problem
by reducing the problem to smaller versions of itself
Has one or more base cases
Implemented using recursive methods

*The base case is a simple case of the problem that we can answer directly
For factorial(), the base case is n = 1
Defining Recursion
Recursive method: a method that calls itself.
Iterative method: a method that uses a loop.
hello(N) prints “Hello” N times.
public void hello(int N) {
public void hello(int N) {
if (N > 0) {
for (int k = 0; k < N; k++)
System.out.println("Hello");
System.out.println("Hello");
hello(N - 1);
} // hello()
}
} // hello()

Iterative, repeats Recursive, calls


the loop N times. itself N times.

Base case: If the N value called recursively is less than 1, exit from the function.
Trace of Recursive hello()
Trace of hello(5) :
public void hello(int N) { Stop when N = 0.
if (N > 0) {
System.out.println("Hello");
hello(N - 1);
}
} // hello()

hello(5)
Print “Hello”
hello(4)
Print “Hello”
Decrement N on hello(3)
Print “Hello”
each recursive hello(2)
Print “Hello”
call. hello(1)
Print “Hello”
hello(0)
Recursion versus Iteration

Recursion is an alternative to iteration.


Languages like LISP and PROLOG use
recursion instead of loops.
Loops use less computational overhead
than method calls.
Effective Design: Efficiency. Iterative
algorithms are generally more efficient
than recursive algorithms that do the
same thing.
Problem Solving with
Recursion
Divide-and-conquer: Divide the problem
into smaller problems.
Self-similarity: Each sub-problem is
similar to the original problem.
Factorial Example:
n! = n * (n-1) * (n-2) * … * 1 Recursion:
4! = 4 * 3!
4! = 4 * 3 * 2 * 1 = 4 * 3! = 24
3! = 3 * 2 * 1 = 3 * 2! = 6
2! = 2 * 1 = 2 * 1! = 2
1! = 1 * 0! = 1
0! = 1
Recursive Definition

Recursive definition of factorial(n):


n! = 1 if n = 0 // Boundary (or base) case
n! = n * (n-1)! if n > 0 // Recursive case
Divide-and-Conquer: n! is
defined in terms of a smaller,
self-similar problem, (n-1)!

Effective Design: Recursive Definition.


The base case serves as the bound for the
algorithm.
The recursive case defines the nth case in
terms of the (n-1)st case.
Example: Factorial of a number

public static int fact(int num)


{
if(num == 0) BASE CASE
return 1;
else
return num * fact(num – 1);
}

4! = 4 * 3 * 2 * 1 = 4 * 3! = 24
3! = 3 * 2 * 1 = 3 * 2! = 6
2! = 2 * 1 = 2 * 1! = 2
1! = 1 * 0! = 1
0! = 1
Trace of Recursive Factorial
Recursive printString(s)
Head-and-tail recursion: print the head, and
recursively print the tail of the string.
Head of String s: s.charAt(0)
Tail of String s: s.substring(1)
For Hello, print H and recursively print ello.
public void printString(String s) {
if (s.length() == 0)
return; // Base case: do nothing
else {
System.out.print(s.charAt(0)); // Recursive case: print head
printString(s.substring(1)); // Print tail of the string
}
} // printString()
Recursion parameter.
Tracing printString(“hello”)
Effective Design
Recursive Progress. Each recursive call must
make progress toward the bound, or base
case.
Recursion and Parameters. Recursive
methods use a recursion parameter to control
progress toward its bound.
Head/Tail Algorithm. Divide a sequential
structure into its head and tail. Process the
head, and recurse on the tail.
Printing the String Backwards
Reverse Head/Tail: Recursively process the
tail, then process the head:
public void printReverse(String s) {
if (s.length() > 0) { // Recursive case:
printReverse(s.substring(1)); // Print tail of the string
System.out.print(s.charAt(0)); // Then print the first char
}
} // printReverse()

For Hello, recursively printing ello then


printing H will give olleH
Tracing printReverse("hello")

public void printReverse(String s) {


if (s.length() > 0) {
printReverse(s.substring(1));
System.out.print(s.charAt(0));
}
} // printReverse()

Last-In-First-Out (LIFO).
Procedure call follows a
LIFO protocol.
Counting Characters in a String
Count the number of ch’s in a string s.
Algorithm: Count the head of s then
recursively count the ch’s in the tail of s.
Embeded
/** recursive call
* Pre: s is a non-null String, ch is any character
* Post: countChar() == the number of occurrences of ch in s
*/
public int countChar(String s, char ch) {
if (s.length() == 0) // Base case: empty string
return 0;
else if (s.charAt(0) == ch) // Recursive case 1
return 1 + countChar(s.substring(1), ch); // Head equals ch
else // Recursive case 2
return 0 + countChar(s.substring(1), ch); // Head is not the ch
} // countChar()

Return is done after the recursive call.


Tracing countChar("dad", 'd')

Embedded recursive call:


the results are accumulated.

public int countChar(String s, char ch) {


if (s.length() == 0)
return 0;
else if (s.charAt(0) == ch)
return 1 + countChar(s.substring(1), ch);
else
return 0 + countChar(s.substring(1), ch);
} // countChar()
Exercise
Do the trace of the previous method for the
following String and Character:
String: “maman”
Character: ‘a’

You might also like