前言

      递归思路还是很锻炼程序员的逻辑能力的,尤其在数据结构二叉树中递归的理解和使用是极其重要的,今天就给大家分享一下对于递归,我们应该从哪些方面着手。

目录

1.递归基本概念

2.递归基本思路

3.经典案例图解+文字描述

3.1 求斐波那契数列第n位

3.1.1 为什么用非递归求斐波那契数列第n位是首先选择?

3.2 汉诺塔

3.3 顺序打印一个数的每一位

3.4 求一个数每一位相加之后的和

3.5 求n的阶乘


1.递归基本概念

自身包含自己 2) 将复杂的原问题拆分成多个子问题,且子问题与原问题的解法相同,将子问题一个个解决之后,复杂的原问题就解决了。

2.递归基本思路

注意:子问题必须要与原问题的解法相同。

           2)递归结束条件,也就是最简单的子问题,是递归的出口。

当方法执行结束之后,会回到调用位置继续往下执行。

3.经典案例图解+文字描述

3.1 求斐波那契数列第n位

        3.1.1 为什么用非递归求斐波那契数列第n位是首先选择?

                   首先斐波那契数列是这样的数列:1 1 2 3 5 8 13 21 34 55 ...........

                   假设我们求第4位的斐波那契数。

                   根据递归思路我们可以将原问题分解成如下子问题:

                    f(4) = f(3) + f(2) ----> f(3) = f(2) +  f(1) ..........如图:

java 计算递归调用的次数 java递归算法经典实例_java 计算递归调用的次数

 由图可知,递归的终止条件为 n = 1时,斐波那契数列第1项为1,第2项为第1项+0,第3项为第2项+第1项 = 2,所以我们能得到递推式 f(n) = f(n-1) + f(n-2),由此我们可以这样写代码:

//递归求斐波那契数列的第 N 项
    public static int factorialN(int num){
        // 因为第一项和第二项都为1,所以我们从第三项开始递归
        if(num == 1 || num == 2) return 1; 
        else return factorialN(num-1) +factorialN(num-2);
    }

其具体过程图如下:

java 计算递归调用的次数 java递归算法经典实例_斐波那契数列_02

大家有没有觉得对递归流程更加清楚了呢? 冲冲冲继续!到这里大家可能已经发现了n=2和n=1的斐波那契数重复计算了多次,当n越大,重复计算次数越多,所以我们在计算斐波那契数的时候尽量采用非递归形式也就是循环的方式去计算,避免空间浪费及执行效率降低。

//非递归求斐波那契数列的第 N 项
    public static int factorialN(int num){
        int a = 0,b = 1,c = 0;
        while(tmp--){
          c = a + b;
          a = b;
          b = c;
        }
        return c;
    }

3.2 汉诺塔

         汉诺塔就是有三个盘A,B,C,将A盘上n个盘子移动到C,且要保证三个盘上的盘子是从小到大放置的。如图:

java 计算递归调用的次数 java递归算法经典实例_java 计算递归调用的次数_03

 

java 计算递归调用的次数 java递归算法经典实例_斐波那契数列_04

由图可知,递推结束条件为 n = 1时,A--->C。我们可以将三个位置当做起始位置,中转位置,终点位置(A,B,C位置任意)。借用递归,我们就不用一一的去了解盘子每一步该怎么移动,直接将A位置的n-1个盘子移动到B位置,然后A位置最后一个盘子移动到C位置,最后再将B位置上的n-1个盘子借用A位置移动到C位置上就好了。我们可以这样写代码:

//移动过程
    public static void towerOfHanoiPrint(int n,char posA,char posB,char posC){
         if(n == 1) {
             move(posA,posC);
             return;
         }
         //将A位置的n-1个盘借助C位置移动到B位置上
         //A位置:起始位置 B位置:终点位置 C位置:中转位置
         towerOfHanoiPrint(n-1,posA,posC,posB);
         //将A位置剩下的最后一个盘直接移动到C位置上
         //A位置:起始位置 B:中转位置 C:终点位置
         towerOfHanoiPrint(1,posA,posB,posC);
         //最后将B位置的n-1个盘借助A位置移动到C位置
         //A位置:中转位置 B位置:起始位置 C位置:终点位置
         towerOfHanoiPrint(n-1,posB,posA,posC);
    }

    public static void move(char start,char end){
        System.out.print(start+"->"+end+" ");
    }

具体递归过程:

java 计算递归调用的次数 java递归算法经典实例_算法_05


3.3 顺序打印一个数的每一位

         题目示例:1234 使用递归打印:1 2 3 4。如图:

java 计算递归调用的次数 java递归算法经典实例_java 计算递归调用的次数_06

由图可知,递归终止条件为n<10时,如果n>10时,则需要对其%后继续/10。具体代码实现:

//按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4) (递归)
    public static void factorialPrint(int num) {
        if(num/10 == 0) {//条件也可以是num < 10
            System.out.print(num%10+" ");
            return;
        }
        factorialPrint(num/10);
        System.out.print(num%10+" ");
    }

具体递归过程:

java 计算递归调用的次数 java递归算法经典实例_斐波那契数列_07

3.4 求一个数每一位相加之后的和

         这道题跟上一道有些类似,都得把每一位得出来,不多说,直接上图:

java 计算递归调用的次数 java递归算法经典实例_非递归_08

 由图可知,递归终止条件为n < 10 ,递推式为f(n) = n%10 + f(n/10),具体代码实现:

//写一个递归方法,输入一个非负整数,返回组成它的数字之和
    public static int sum_fac(int num) {
        if(num/10 == 0) return num;//num < 10也可
        else return num%10 + sum_fac(num/10);
    }

具体递归过程:

java 计算递归调用的次数 java递归算法经典实例_java 计算递归调用的次数_09


注:所有的递归都是在满足递归终止条件后才能返回哦! 

3.5 求n的阶乘

         相信大家经过以上几个经典案例能够对递归过程了解多一点。所以相信阶乘也对大家不难。因为n! = 1*2*3*...n;所以我们可以得出其递归终止条件是n = 1的时候,且它的递归式为:

f(n) = n * f(n-1),所以这里我直接上代码:

//递归求N的阶乘
    public static int factorialMulN(int num){
        if(num == 1) return 1;
        else return num*factorialMulN(num-1);
    }

具体递归过程:

java 计算递归调用的次数 java递归算法经典实例_斐波那契数列_10