纠结了好久的递归算法,终于彻底搞明白...

对于递归算法,我之前是真的半懂不懂,着实无奈,总抱着以后能懂的想法。现在学到的内容却发现递归是真的不懂。平时我们对于递归算法的要求比较低,因为觉得它的效率很低,但是它对于一些问题却能帮我们快速地解决,所以为了彻底搞懂它想了好久,一天两天了吧…希望这篇文章对你有帮助。

1.递归的概念:

一个函数的递归调用是指一个函数在执行过程中出现了直接或间接调用函数本身的调用方式。如果直接调用函数本身,则称为直接递归;如果直接调用本身,则称为直接递归;如果调用另外一个函数,那个函数又调用该函数,则称为间接递归。通俗地来说,递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解。

递归的三要素:
1.明确递归的终止条件
2.给出递归的终止时处理方法
2.提取重复地逻辑,缩小问题规模

2.递归的优缺点:
优点缺点
实现简单,可读性好递归调用,占用空间大,递归太深,易发生栈溢出,可能存在重复计算

递归的强大之处在于它允许用户用有限的语句描述无限的对象(通俗地说,少代码代替多代码)。

3.递归的执行过程:

此图摘取于:递归过程
在这里插入图片描述

4.四种情况输出顺序去理解递归
4.1.数的阶乘(单层递归)

如:4!=423*1的执行过程如下:
在这里插入图片描述

4.2 分三种情况说明递归前后语句的执行情况(单层递归+前后语句)

递归函数中,位于递归调用前的语句和各级被调用函数具有相同的执行顺序;
递归函数中,位于递归调用后的语句的执行顺序和各个调用函数的顺序相反。

第一种:for循环+前语句+递归:
在这里插入图片描述
如果按正常顺序执行代码,当n=3时,每个i都有一个f(2):
在这里插入图片描述
执行过程如下:这个输出就有点类似于二叉树的遍历,一直找,直到撞墙(结束条件),然后递归返回。
在这里插入图片描述
第二种:for循环+递归+后语句及程序输出结果:
在这里插入图片描述
在这里插入图片描述
第三种:for循环+前语句+递归+后语句,综上前面两种,不看结果,现在我们直接来手动输出一遍,其输出顺序如下:
在这里插入图片描述

public class Helloworld{
   static int sum;
    public static void main(String args[]){
       f(3);
    }
    public static void f(int n){
        if(n==1) {
            System.out.println("end....");
            return;
        }
        else {
            for(int i=1;i<=n;i++){
                System.out.println("i="+i+"start");
                f(n-1);
                System.out.println("i="+i+"****");
            }

        }
    }
}
4.3.二叉树的递归遍历(二层递归):

先序遍历(DLR,父节点左孩子节点右孩子节点):DEBAC
在这里插入图片描述
中序和后序就不做模拟,我们可以自己试着去模拟一下。

void preOrder(Bitree bt){///先序遍历
    if(bt==NULL) return;
    printf("%c",bt->data);
    preOrder(bt->lchild);
    preOrder(bt->rchild);
}

中序遍历(LDR,左孩子节点父节点右孩子节点):

void InOrder(Bitree bt){///中序遍历
   if(bt==NULL) return;
   InOrder(bt->lchild);
   printf("%c",bt->data);
   InOrder(bt->rchild);
}

后序遍历(LRD,左孩子节点右孩子节点父节点):

void PostOrder(Bitree bt){///后序遍历
    if(bt==NULL) return;
    PostOrder(bt->lchild);
    PostOrder(bt->rchild);
    printf("%c",bt->data);
}
4.4. 找出可能的合的组合(多层递归)

小米oj:原题
在这里插入图片描述
以1,2 3一共三种为例子:
在这里插入图片描述


import java.util.*;

public class Main {
    static int ans;
    static int num[];
    public static void main(String args[]) {
        Scanner scan = new Scanner(System.in);
        String line;
        while (scan.hasNextLine()) {
            ans = 0;
            line = scan.nextLine().trim();
            // please write your code here
            String [] str = line.split(" ");
            String [] str1 = str[0].split(",");
            num = new int[str1.length];
            int sum = Integer.parseInt(str[1]);
            for(int i=0;i<str1.length;i++) num[i] = Integer.parseInt(str1[i]);

            dfs(sum,num.length-1);
            System.out.println(ans);
        }
    }
    private static void dfs(int target,int cur){
        ///System.out.println("target:"+target+"cur:"+cur);
        if(target<0||cur<0) return;
        System.out.println("target:"+target+"cur:"+cur);
        if(target==0) {
            System.out.println("找到了");
            ans++;
            return;
        }

        dfs(target-num[cur],cur-1);
        System.out.println("---------");
        dfs(target-num[cur],cur);
        System.out.println("---------");
        dfs(target,cur-1);
    }
}

总结:看了这个执行过程,我们可能会感慨,递归算法也不过如此。为什么?因为我们通过动笔去手动输出,彻底搞懂它的执行过程。如果我们对于该概念还不懂,我们可以用数学的方法去理解它,如阶乘递归:f(n) = n* f(fn-1)→f(n)=n* (n-1)* f(n-2)→…结束条件为n==0。函数是不断返回一个值,直到遇到结束条件。(不撞南墙不回头!!!)

5.参考资料

你为什么学不会递归?读完这篇文章轻松理解递归算法
《C语言程序设计》陈东旭和马迪芳版
递归算法的讲解

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值