递归的思想

简介: 递归分别表示递和归的两个动作,“ 函数递,函数归 ”。也就是说递归的本质是自己调用自己。

一、递归的思想



1. 递归分别表示递和归的两个动作,“ 函数递,函数归 ”。也就是说递归的本质是自己调用自己。


2. 函数递归要有两个必要的条件:


(1) 递归需要设置一个终止条件,以此来结束无限调用。

(2) 每一次的递归要无限趋近于这个条件。


如果不满足上面的这两个条件,函数递归就会无限地递归下去,直至栈溢出。栈溢出即表示栈区的内存被占满了。


如下图所示,当我们使用一个函数时,函数内的创建的局部变量都是放在栈区内存中存储的,如果无限递归下去不停止,就会导致栈区的内存超额。比如下面的 f 变量。


8f555e6caff64fc0aca68d6296ba6412.png


二、一些递归的题目



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


思想:


红色线条为递,绿色线条为归。


70ea6e477d6149fe9664f7db689f93f6.jpg


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


分析思路:


d10daf80f2fc432d8df9afa3b1fdf2c8.jpg


总结



  1. 本人最近从 C 转到 Java,将递归又重新学了一遍,好处一在于巩固了算法,好处二在于熟悉新的代码风格,并增加了印象。其实不论是 C 还是 Java,实现的算法和逻辑都是相同的,只是语言不同,风格不同。


  1. 现在慢慢感受到了,语言只是工具,不论什么语言都是来解决问题的,语言不同只是语法层面上的不同,最重要还是要有解决问题的思想。


  1. 关于一些代码的细节部分没有赘述,比如函数内在的一些逻辑,比如递归求斐波那契数列为什么没有迭代法求出来更加高效。因为本篇博客旨在阐明递归的思想,读者可以从我给出的例子自我体会,只需要掌握每个问题的规律即可,没有必要深挖下去。


  1. 下一篇博客十七会分享使用递归来解决青蛙跳台阶和汉诺塔的问题。


ed9aa40284c446bb810914f74a2d39a5.jpg


Over. 谢谢观看哟~

目录
相关文章
|
11月前
|
算法
快排三种递归及其优化,非递归和三路划分
快排三种递归及其优化,非递归和三路划分
47 0
|
11月前
|
人工智能 算法
【算法分析与设计】递归与分治策略(二)
【算法分析与设计】递归与分治策略
|
3月前
|
机器学习/深度学习 C语言
|
3月前
|
机器学习/深度学习 存储 算法
算法学习:递归
算法学习:递归
36 0
|
11月前
|
机器学习/深度学习 算法 编译器
【算法分析与设计】递归与分治策略(一)
【算法分析与设计】递归与分治策略
|
4月前
|
算法
回溯算法思想
回溯算法思想
30 0
|
11月前
|
算法 搜索推荐 Windows
【算法分析与设计】递归与分治策略(三)
【算法分析与设计】递归与分治策略
|
算法 C语言
糊里糊涂的递归和递归经典题(上)
糊里糊涂的递归和递归经典题
糊里糊涂的递归和递归经典题(下)
糊里糊涂的递归和递归经典题(下)
|
存储 算法 程序员
算法学习<3>---递归
算法学习<3>---递归
93 0
算法学习<3>---递归