首页 > 编程语言 >递归算法理解 (一)

递归算法理解 (一)

时间:2023-06-30 22:55:22浏览次数:37  
标签:调用 递归 int void 算法 理解 static public

Introduction

 递归算法是一种直接或者间接调用自身函数或者方法的算法。递归算法的实质是把问题分解成规模缩小的同类问题的子问题,然后递归调用方法来表示问题的解。递归算法对解决一大类问题很有效,它可以使算法简洁和易于理解。递归算法,其实说白了,就是程序的自身调用。它表现在一段程序中往往会遇到调用自身的那样一种coding策略,这样我们就可以利用大道至简的思想,把一个大的复杂的问题层层转换为一个小的和原问题相似的问题来求解的这样一种策略。递归往往能给我们带来非常简洁非常直观的代码形势,从而使我们的编码大大简化,然而递归的思维确实很我们的常规思维相逆的,我们通常都是从上而下的思维问题, 而递归趋势从下往上的进行思维。这样我们就能看到我们会用很少的语句解决了非常大的问题,所以递归策略的最主要体现就是小的代码量解决了非常复杂的问题。
递归就是方法里调用自身。
在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。
递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等,所以一般不提倡用递归算法设计程序。
  递归算法要求。递归算法所体现的“重复”一般有三个要求:
  (1) 是每次调用在规模上都有所缩小(通常是减半);
  (2) 是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);
  (3) 是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

演示

演示 1

1、使用方法嵌套的方式来模拟递归的执行流程

public class RecursionFunction {
    void a() {
        b();
        System.out.println("a");
    }

    void b() {
        c();
        System.out.println("b");
    }

    void c() {
        d();
        System.out.println("c");
    }

    void d() {
        System.out.println("d");
    }

    public static void main(String[] args) {

        RecursionFunction demo = new RecursionFunction();
        demo.a();
    }
}

  • 注意
    1、从上面内容我们可以看到从方法 a -> b -> c -> d 的执行都是先执行的调用链的最深处
    2、方法的嵌套是有边界的 d 就是我们的调用边界
    3、上面这种调用方式就是我们在遍历树结构时所说的后续遍历

演示二

1、使用方法嵌套的方式来模拟递归的执行流程

public class RecursionFunction {


    void a() {
        // 执行逻辑
        System.out.println("a");
        b();
    }

    void b() {
        // 执行逻辑
        System.out.println("b");
        c();
    }

    void c() {
        // 执行逻辑
        System.out.println("c");
        d();
    }

    void d() {
        // 执行逻辑
        System.out.println("d");
    }

    public static void main(String[] args) {

        RecursionFunction demo = new RecursionFunction();
        demo.a();
    }
}

  • 注意
    1、上面这种调用方式就是我们在遍历树结构时所说的后续前序遍历
    2、只有一种调用链路不存在中序遍历哈

递归实战

实战 1 (前序遍历)

1、数组的递归遍历 (注意事项:递归需要有边界;需要注意递归函数的返回值)

public class TraverseArray {

    private static final int LEN = 10;

    private static int[] array = new int[LEN];

    static {
        for (int i = 0; i < LEN; i++) {
            array[i] = i;
        }
    }

    /**
     * 前序遍历
     * @param index
     */
    public static void traverseRecursion(int index) {
        // 递归出口
        if (index == LEN) {
            System.out.println();
            return ;
        }
        // 执行逻辑
        System.out.printf("%d " , array[index]);
        // 递归调用
        traverseRecursion(index + 1);
    }

    public static void main(String[] args) {
        traverseRecursion(0);
    }
}

  • 注意
    1、有没有发现这个例子和我们上面的 演示1 的执行流程特别像
    2、递归函数的构成通常有 (1、递归边界 2、执行逻辑 3、递归调用)
    3、通过调整递归逻辑我们可以得到不同的结果

实战二 (后继遍历)

1、数组的递归遍历 (注意事项:递归需要有边界;需要注意递归函数的返回值)


public class TraverseArray {

    private static final int LEN = 10;

    private static int[] array = new int[LEN];

    static {
        for (int i = 0; i < LEN; i++) {
            array[i] = i;
        }
    }

    /**
     * 前序遍历
     * @param index
     */
    public static void traverseRecursion(int index) {
        // 递归出口
        if (index == LEN) {
            System.out.println();
            return ;
        }
        // 递归调用
        traverseRecursion(index + 1);
        // 执行逻辑
        System.out.printf("%d " , array[index]);
    }

    public static void main(String[] args) {
        traverseRecursion(0);
    }
}

1、通过调整执行逻辑我们就可以达到不一样的执行效果
2、前序遍历是先执行方法逻辑在调用方法,如上演示 1 ,后续遍历是先调用方法在执行方法逻辑,如上演示 2

实战三

1、使用递归计算从 1 - 100 的和

public class ZeroToHundredSum {


    public static int answer = 0;

    public static final  int Hundred = 100;


    public static int getSum(int val) {
        if (val == Hundred + 1) {
            return answer;
        }
        answer = answer + val;
        return getSum(val + 1);
    }

    public static void main(String[] args) {
        getSum(1);
        System.out.println(answer);
    }
}

\

  • 注意
    1、使用时需要注意 answer 的作用域,全局作用域和方法及作用域
    2、在计算最终结果或者中间结果时需要使用到全局作用域
    3、方法及作用域演示代码
public class ZeroToHundredSum2 {

    /**
     * 使用较小返回进行计算
     */
    public static final  int Hundred = 2;

    public static int getSum(int val) {
        int answer = 0;
        answer = answer + val;
        if (val == Hundred) {
            return answer;
        }
        return getSum(val + 1);
    }

    public static void main(String[] args) {
        int answer = getSum(1);
        System.out.println(answer);
    }
}

  • 注意
    1、方法及作用域的值,在最为结果返回时只会计算最后一次的结果,如上图

标签:调用,递归,int,void,算法,理解,static,public
From: https://www.cnblogs.com/ayizzz/p/17517992.html

相关文章

  • 数据结构和算法-2023.06.30
    动态链表的生成和初衷......
  • 四种语言刷算法之LRU 缓存
    力扣146. LRU缓存1、Ctypedefstruct{intkey;intval;UT_hash_handlehh;}LRUCache;LRUCache*usr=NULL;intsize=0;LRUCache*lRUCacheCreate(intcapacity){size=capacity;returnusr;}intlRUCacheGet(LRUCache*obj,intke......
  • 万字长文解析最常见的数据库恢复算法: ARIES
    万字长文解析最常见的数据库恢复算法:ARIES首发地址:https://mp.weixin.qq.com/s/Kc13g8OHK1h_f7eMlnl4AwIntroduction上图中为基于WAL的数据库的一种可能的架构情况。其中,In-MemoryData为数据库数据在内存中的组织形式,可以是B树,也可以是hashtable或者其他可能的......
  • PID 的搜索算法(PSA)附matlab代码
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 【基础算法】八大排序算法:直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序(快排)
    ✔️前言......
  • 数据结构和算法的关系
    1.数据结构是一门研究组织数据方式的学科,有了编程呢个语言也就有了数据结构,学好数据结构可以编写出更加漂亮,更加有效率的代码2.要学好数据结构就要多多考虑如何将生活中遇到的问题,用程序去实现解决3.程序=数据结构+算法4.数据结构是算法的基础,换言之,要学好算法,需要把数据结构学......
  • 数据结构与算法
    数据结构和算法的重要性:1.算法是程序的灵魂,优秀的程序可以在海量数据计算时,依然保持高速计算。2.一般来讲,程序会使用了内存计算框架(比如Spark)和缓存技术(比如Redis等)来优化程序,再深入的思考一下,这些计算框架和缓存技术,他的核心功能是哪个部分呢?3.拿实际工作经历来说,在Unix下开发......
  • JavaScript aglo 算法 时间复杂度
    https://www.bigocheatsheet.com/https://www.hello-algo.com/chapter_preface/about_the_book/ gpt的回答好的,下面给出这些算法的JavaScript例子,并给出它们的时间复杂度分析:O(1)-常数时间复杂度:javascriptCopyCodefunctionconstantTimeAlgorithm(n){return2+......
  • C#实现所有经典排序算法
    C#实现所有经典排序算法//选择排序classSelectionSorter{privateintmin;publicvoidSort(int[]arr){for(inti=0;i<arr.Length-1;++i){min=i;for(intj=i+1;j<......
  • 保龄球Split算法
    需求:剩下两个或两个以上的球瓶它们之间没有球瓶;例如:7-9或者3-10剩下两个或两个以上的球瓶,他们前面的球瓶被击倒,例如:5-6保龄球位置信息如下图: privateintSplitBall(stringpositionStr){//第一个球必须倒并且未倒的球大于1个......