Understanding Recursion in Java with examples

1. What is recursion

Recursion is when a function refers to itself within it own definition.

We can distinguish between two types of recursion:

Tail Recursion – the function first performs some processing and only then calls itself. Tail recursion is similar to a loop in that it performs all its computation before performing the next recursive call;

Head Recursion – any recursive function which is not Tail Recursive.

2. Recursion in Java

Recursion in Java is when a method calls itself within it own definition.

2.1 Head Recusrion Example

public int head(int n)  {
	// compute from n
	int result1 = ... 
	// compute from n and result1
	boolean condition = ... 
	
	if(condition) {
   		return head(result1);
	}

	// compute from n and result1
	int result2 = ... 
	return result2;     
}

2.2 Tail Recursion Example

public int tail(int n)  {
	// compute from n
	int result1= ... 
	// compute from n and result1
	boolean precondition = ... 
	
	if(precondition) {
   		return result1;
	} 
	
	// compute from n and result1
	int result2 = ... 
	return tail(result2);    
}

3. Advantages of using Recursion in Java

Recursive methods are generally simpler to code and maintain than iterative methods.

4. Disadvantages of using Recursion in Java

Recursion requires that the method repeatedly pushes itself onto the Java stack. Recursion generally takes more memory than iterative methods. Also, if the recursion is too deep it will exhaust the capacity of the stack and result in a StackOverflowError.

5. Recursion vs Iteration vs Dynamic Programming

Simplicity

  • Recursion: Often easier to implement and maintain.
  • Iteration: Often difficult to implement and maintain.
  • Dynamic Programming: Often easier to implement and maintain.

Performance

  • Recursion: Often has poorer performance.
  • Iteration: Iteration involves loops which the compiler can optimize. So iteration often has better performance.
  • Dynamic Programming: Depends on the problem.

Memory

  • Recursion: Generally takes more memory.
  • Iteration: Often takes less memory.
  • Dynamic Programming: Often takes less memory since one only stores the minimal amount of data required.

6. Examples

6.1 Fibonacci Sequence

The n-th term, f(n), of the Fibonacci sequence is defined as follows:

	n = 0 : f(0) = 0
	n = 1 : f(1) = 1
	n > 1 : f(n) = f(n-2) + f(n-1)

It is easy to see that the first few terms of the Fibonacci sequence are

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

Recursion version

public static int fibonacci(int n) {
	switch(n) {
		case 0: return 0;
		case 1: return 1;
		default: return fibonacci(n-2) + fibonacci(n-1);
	}
}

Iteration version

public static int fibonacciIterationVersion(int n) {
	switch(n) {
		case 0: return 0;
		case 1: return 1;
		default: 
			int[] f = new int[n + 1];
			f[0] = 0;
			f[1] = 1;
			for (int i = 2; i < n + 1; i++) {
				f[i] = f[i - 2] + f[i - 1];
			}    	
			return f[n];
	}
}

Dynamic version

public static int fibonacciDynamicVersion(int n) {
	switch(n) {
		case 0: return 0;
		case 1: return 1;
		default: 
			int[] f = new int[3];
			f[0] = 0;
			f[1] = 1;
			for (int i = 0; i < n; i++) {
				f[2] = f[0] + f[1];
				f[1] = f[0];
				f[0] = f[2];
			}
			return f[2];
	}
}

6.2 Factorials

The factorial of a non-negative integer n is written as n!. It is defined as fallows:

	0! = 1
	1! = 1
	n! = n * (n-1)!

The first few factorials are

	0! = 1
	1! = 1
	2! = 2
	3! = 6
	4! = 24
	5! = 120

Recursion version

public static int factorialRecursionVersion(int n) {
	switch(n) {
		case 0: return 1;
		case 1: return 1;
		default: return n * factorialRecursionVersion(n-1);
	}
}

Iteration version

public static int factorialIterationVersion(int n) {
	switch(n) {
		case 0: return 1;
		case 1: return 1;
		default: 
			int[] f = new int[n + 1];
			f[0] = 1;
			for (int i = 1; i < n + 1; i++) {
				f[i] = i * f[i - 1];
			}   	
			return f[n];
	}
}

Dynamic version

public static int factorialDynamicVersion(int n) {
	switch(n) {
		case 0: return 1;
		default: 
			int result = 1;
			for (int i = 1; i < n + 1; i++) {
				result *= i;
			}   	
			return result;
	}
}

7. Conclusion

In this article, we learned about recursive programming and compared it to iterative and dynamic programming.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.