In this post, we will solve the classic school problem of calculating the factorial of a positive integer, using different Java algorithms.
Note: In all the algorithms below, we assume that the input is > 1.
1. Iterative FactorialIn this algorithm, we use a standard for-loop and increment the variables i
and result
at each iteration:
static int iterativeFactorial(final int n) { int result = 1; for (int i = 1; i <= n; i++) { result *= i; } return result; }2. Recursive Factorial
Here is the recursive version (the function calls itself):
static int recursiveFactorial(final int n) { return n == 1 ? 1 : n * recursiveFactorial(n - 1); }
Recursion lets you get rid of variables that are updated at each iteration. Typically, making a recursive function call is more expensive than iteration because each time the function is called, a new stack frame has to be created on the call stack to hold the state of each function call. Therefore, the memory consumed by the recursive function is proportional to the size of its input. You may even get a StackOverflowError
with a large input.
Here's a tail-recursive definition of factorial. The recursive call is the last thing that happens in the function. In contrast, in our previous definition of factorial, the last thing was n
multiplied by the result of the recursive call.
static int tailRecursiveFactorial(final int n) { return tailRecursiveFactorialHelper(n, 1); } private static int tailRecursiveFactorialHelper(final int n, final int acc) { return n == 1 ? acc : tailRecursiveFactorialHelper(n - 1, n * acc); }
Tail-recursive functions can be optimised by the compiler in some programming languages. Instead of storing each intermediate result of the recursion onto different stack frames, a single stack frame can be reused instead, because there's no need to keep track of intermediate results. Unfortunately, Java does not support this kind of optimisation, but you might want to take this approach anyway, in case the compiler is optimised in the future. Other JVM languages (e.g. Scala) can optimise tail-recursion.
4. Stream FactorialFinally, Java 8 streams provide a simple, declarative way of defining factorial:
static int streamFactorial(final int n) { return IntStream.rangeClosed(1, n).reduce(1, (a, b) -> a * b); }
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.