递归思想详解+多个简单案例(JAVA实现)

  • Post author:
  • Post category:java


前言

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


目录


1.递归基本概念


2.递归基本思路


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


3.1 求斐波那契数列第n位


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


3.2 汉诺塔


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


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


3.5 求n的阶乘


1.递归基本概念

一个方法在执行过程中调用自身,就称为递归。相当于数学上的数学归纳法,肯定有一个起始条件,然后有一个递推公式。其特点:1)

自身包含自己

2) 将

复杂的原问题拆分成多个子问题,且子问题与原问题的解法相同

,将子问题一个个解决之后,复杂的原问题就解决了。

2.递归基本思路

1)首先将原问题划分成其子问题。


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

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) ……….如图:

由图可知,递归的终止条件为 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);
    }

其具体过程图如下:

大家有没有觉得对递归流程更加清楚了呢? 冲冲冲继续!到这里大家可能已经发现了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,且要保证三个盘上的盘子是从小到大放置的。如图:

由图可知,递推结束条件为 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+" ");
    }

具体递归过程:


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

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

由图可知,递归终止条件为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+" ");
    }

具体递归过程:

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

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

由图可知,递归终止条件为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);
    }

具体递归过程:




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





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);
    }

具体递归过程:


以上就是跟大家分享的递归知识,相信大家肯定能更好理解递归!!!是不是递归其实没有你想象的那么难~~~



版权声明:本文为weixin_47851265原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。