一、递归的思想
1. 递归分别表示递和归的两个动作,“ 函数递,函数归 ”。也就是说递归的本质是自己调用自己。
2. 函数递归要有两个必要的条件:
(1) 递归需要设置一个终止条件,以此来结束无限调用。
(2) 每一次的递归要无限趋近于这个条件。
如果不满足上面的这两个条件,函数递归就会无限地递归下去,直至栈溢出。栈溢出即表示栈区的内存被占满了。
如下图所示,当我们使用一个函数时,函数内的创建的局部变量都是放在栈区内存中存储的,如果无限递归下去不停止,就会导致栈区的内存超额。比如下面的 f 变量。
二、一些递归的题目
1. 递归求阶乘
程序清单1:
public class Test1 {
public static void main(String[] args) {
int n = 3;
System.out.println(fac(n));
}
public static int fac(int n){
if(n == 1){
return 1;
}else{
return n * fac(n- 1);
}
}
}
//3*2*1 = 6
思想:
红色线条为递,绿色线条为归。
2. 递归求和
程序清单2:
public class Test2 {
public static void main(String[] args) {
int n = 10;
System.out.println(fac(n));
}
public static int fac(int n){
if(n==1){
return 1;
}else{
return n + fac(n- 1);
}
}
}
//10+9+8+...+2+1 = 55
3. 递归顺序打印一个给定数字中各个位数
程序清单3:
public class Test3 {
public static void main(String[] args) {
int n = 1357;
fac(n);
}
public static void fac(int n){
if(n/10 == 0) {
System.out.print(n % 10+ " ");
}else{
fac(n / 10);
System.out.print(n % 10+ " ");
}
}
}
//输出 1 3 5 7
分析:
(1) 上面代码通过 n / 10 和 n % 10 来进行转换位数,这里不再赘述
(2) 这里递归的终止条件是 n / 10 == 0,也就是说,碰到给定数字的个位数的时候,就 “ 归 ”
4. 递归输出一个数中各个数字相加之和
程序清单4:
public class Test4 {
public static void main(String[] args) {
int n = 1357;
System.out.println(fac(n));
}
public static int fac(int n){
if(n/10 == 0) {
return ( n % 10 );
}else{
return fac(n/10) + n % 10;
}
}
}
// 1+3+5+7 = 16
5. 斐波那契数列的实现
0 1 1 2 3 5 8 13 21 34 55 89…
斐波那契数列的特点:
(1) F(0) = 0,F(1) = 1,F(2) = 1
(2) 当 n >= 2,F(n) = F(n - 1) + F(n - 2)
特点1就是终止条件,特点2就是实现规律的公式
程序清单5(递归法):
public class Test5 {
public static void main(String[] args) {
int n = 10;
for (int i = 0; i <= n; i++) {
System.out.println(fib(i));
}
}
public static int fib(int n){
if(n == 0){
return 0;
}
if(n==1 || n==2){
return 1;
}else{
return fib(n-1)+ fib(n-2);
}
}
}
//输出 0 1 1 2 3 5 8 13 21 34 55
程序清单5(迭代法):
public class Test5 {
public static void main(String[] args) {
int n = 10;
fib(n);
}
public static void fib(int n){
int a = 0;
int b = 1;
for (int i = 0; i <= n; i++) {
if(i==0 || i==1){
System.out.println(i);
}
else{
int c = a + b;
a = b;
b = c;
System.out.println(c);
}
}
}
}
//输出 0 1 1 2 3 5 8 13 21 34 55
分析思路:
总结
- 本人最近从 C 转到 Java,将递归又重新学了一遍,好处一在于巩固了算法,好处二在于熟悉新的代码风格,并增加了印象。其实不论是 C 还是 Java,实现的算法和逻辑都是相同的,只是语言不同,风格不同。
- 现在慢慢感受到了,语言只是工具,不论什么语言都是来解决问题的,语言不同只是语法层面上的不同,最重要还是要有解决问题的思想。
- 关于一些代码的细节部分没有赘述,比如函数内在的一些逻辑,比如递归求斐波那契数列为什么没有迭代法求出来更加高效。因为本篇博客旨在阐明递归的思想,读者可以从我给出的例子自我体会,只需要掌握每个问题的规律即可,没有必要深挖下去。
- 下一篇博客十七会分享使用递归来解决青蛙跳台阶和汉诺塔的问题。
Over. 谢谢观看哟~