递归方法就是直接或间接调用自身的方法。
- 最简单的情况称为基础情况或终止条件;
- 而遇到其余情况就应将问题简化为子问题,子问题在本质上和原始问题是一样的,但是更简单也更小。
因为子问题与原始问题具有相同的性质,所以可以用不同的参数来调用这个方法,这称作递归调用。
递归实现简单、直接,但是并不高效。
下面以计算斐波纳挈数为例解释调用过程:
java code:
import java.util.Scanner;
public class ComputeFibonacci{
public static void main(String[] args){
Scanner input=new Scanner(System.in);
System.out.print("Enter an index for the Fibonacci number: ");
int index=input.nextInt();
System.out.println("Fibonacci number at index "+index+" is "+fib(index));
}
public static long fib(long index){
if(index==0)
return 0;
else if(index==1)
return 1;
else
return fib(index-1)+fib(index-2);
}
}
在Java中,操作数是从左向右计算的,所以在完全计算完fib(3) 后才会调用fib(2)。
步骤如下标号:
从这里我们可以看到会出现很多重复的递归调用,而除了大量的递归调用,计算机还需要更多的时间和空间来运行递归的方法。
递归程序可能会耗尽内存,引起StackOverflowError。
任何用递归解决的问题都可以用迭代非递归地解决。那么我们为什么还要用递归呢?因为在某些情况下,本质上有递归特性的问题很难用其他方法解决,而递归可以给出一个清晰、简单的解决方案。(例如:目录大小问题、汉诺塔问题和分形问题,不使用递归很难解决)
从某种程度上讲,递归提供了某种层次的抽象,这种抽象对用户隐藏迭代和其他细节。