递归问题

一、递归的定义

定义:程序函数直接或间接调用自身

二、递归的注意事项

-----递归不是无限循环,递归的次数必须是有限的!-----

---如果没有终止条件,会发生栈溢出(StackOverflowError)---

  • 每次执行一个方法会在JVM-栈中开辟一个内存空间,用于存放方法所需的数据,

  • 比如方法的局部变量、对象引用

注意事项

  • (1)递归必须有出口(终止条件)

  • (2)每次递归,范围逐渐缩小

    例子:计算累加和

    •   

      public class RecursionDemo1 {
          /**
           * 计算累加和
           * @param start,开始累加的值
           * @param end,结束累加的值
           * @return int 返回累加的结果
           */
          public static int addRecursion(int start,int end){
              //递归出口
              if (start == end){
                  return end;
              }
      ​
              //递归调用,每次递归,范围缩小
              return start + addRecursion(start+1,end);
          }
      ​
          @Test
          public void testAddRecursion(){
              int i = RecursionDemo1.addRecursion(1, 3);
              System.out.println(i);
          }
      }

       

        

    • 1627797757827

    • 方法执行完,出栈!

  • 用递归还是循环

    • 优势:简洁明了(用循环实现的用递归一定可以实现)

    • 劣势:循环速度快(但有些场景循环实现不了,必须使用递归)

    • 总结:优先使用循环,循环搞不定使用递归

三、递归的练习

1、实现斐波那契数列(求当前值和和)

(1)循环实现

//输出指定的值,以及所有值的总和  
public static int feboUsewhile(int num) {
        //分析,当前的数的和,等于前2个数的和(NUM =1\2直接给定)
        int key = 0;
        int a = 1;
        int b = 1;
        int sum = 0;
​
        for (int i = 1; i <= num; i++) {
            if (i == 1 || i == 2) {
                key = 1;
            }else{
                key = a + b;    //计算当前的数的和
                a = b;      // 设置新的需要被加数
                b = key;
            }
            sum += key;
            System.out.print(" " + key);//输入当前数的值
        }
        return sum;//返回总和
//        }
    }

 

(2)递归调用

//返回指定的值(递归)
private int feboUseRecursion(int num){
        //1、终止条件,num = 1或2时,返回值为1;
        if (num == 1){
            return 1;
        }else if(num == 2){
            return 1;
        } else{
            //return value(num - 1) + value(num-2);前num-1个数的和+当前的值=前num-1个数的和 +(sum())
            int i = feboUseRecursion(num -1) + feboUseRecursion(num -2);
            return i;
        }
​
    }
​
//求和,循环
public int sum(int num){
    int sum = 0;
    int value;
    for (int i = 1; i <= num; i++) {
        value = feboUseRecursion(i);
        sum += value;
        System.out.println(value);
    }
    return sum;
}
​
//另外附: 
//直接打印数量无返回值,num最小从1开始,one:0,two:1,index:1
    private void feboUseRecursion2(int num,int one,int two,int index){
        if (num == 1){
            System.out.println(1);
            return;
        }
        //1、终止条件,num == index;
        if (index <= num){
            int sum = one + two ;
            System.out.println(sum);
            feboUseRecursion2(num,two,sum,index+1);
            //return value(num - 1) + value(num-2);前num-1个数的和+当前的值=前num-1个数的和 +(sum())
        }
​
    }

 

2、汉诺塔问题:

public void hannuotaRecursion(int num, char start, char mid, char end){
    if (num == 1){
    move(1,start,end);
    }else{
    hannuotaRecursion(num-1,start,end,mid);//将N-1个盘子从开始移到中间
    move(num,start,end);
    hannuotaRecursion(num-1,mid,start,end);//将N-1个盘子从中间移到最后
    }
}

 

 四、总结

 (1)递归可视为循环的简化升级版,注意

  (1)辨别递归出口

     (2)确定递归的内容,递归范围应该逐渐缩小,接近出口

(2)为了更好的理清思路,达到最终的实现。可以先分析循环的实现思路,并且在实现递归时,将功能拆分的尽可能细,循环能实现的,单独拎出来

 

posted @ 2021-08-01 19:16  低手寂寞  阅读(137)  评论(0)    收藏  举报