首页 > 其他分享 >递归详细含图解析

递归详细含图解析

时间:2024-12-02 18:58:57浏览次数:7  
标签:arr last 递归 int static return 解析 含图

1 递归定义: 自己调用自己

2 递归分类:
·- 直接递归:方法自身调用自己。
·- 间接递归:A方法调用B方法,B方法调用C方法,C方法再调用A方法。

3 注意事项
·递归一定要有条件限定,保证递归能够停止下来,否则会形成死循环并发生栈内存溢出StackOverflowError)。
·禁止构造方法递归。
·内层函数调用(子调用)完成,外层函数才能算调用完成【内层函数调用的时候,外层函数中引用的变量不会被JVM回收】!!!!
·递归就是“递”到最后,将结果一层一层往回“归”。
·尾递归的语言: scala 和 c++ 语言。
·尾调用: return语句的返回值是返回调用递归方法的返回值 就不需要调用递归之后 再回来“归”的过程

4 单路递归
定义:(递归函数只包含一个自身调用):
单路递归案例: 阶乘、二分查找、冒泡排序、插入排序

代码实现:

	//阶乘案例
	privite int jiecheng(int n){
		if (n == 1){
			return 1;
		}
		return n * jiecheng(n-1)
	}
	public static void main[String[] args](){
		int value = jiecheng(5);
		System.out.println(value);
	}

图理解
在这里插入图片描述

5 多路递归:
定义:(递归函数包含多个自身调用)
多路递归案例:斐波那契数列【含兔子问题、青蛙跳台阶】、汉诺塔、杨辉三角。
图理解:
在这里插入图片描述

原来版本: 时间复杂度O(1.618的n次方)
改进版本:时间复杂度O(n)   代价: 增加了额外的空间

代码实现

//斐波那契数列案例
package SF_DiGui;  
  
import java.util.Arrays;  
  
public class Fibonacci {  
    public static void main(String[] args) {  
        System.out.println(f1(5));  
        System.out.println(Fibonacci(5));  
    }  
  
    //原始版本  
    public static int f1(int n) {  
        //从第三项开始 每一项的值为前两项之和  数学定义 F(0) = 0,F(1) = 1, F(n) = F(n - 1) + F(n - 2)(n ≥ 2,n ∈ N*)。  
        //TODO 初始化前两项  
        if (n == 0) {  
            return 0;  
        }  
        if (n == 1) {  
            return 1;  
        }  
        return f1(n - 1) + f1(n - 2);  
    }  
  
    //改进版本  
    private static int Fibonacci(int n) {  //斐波那契数列从索引0开始  记忆数组需要n+1个元素  
        int[] cache = new int[n + 1];  
        Arrays.fill(cache, -1);  
        cache[0] = 0;  
        cache[1] = 1;  
        return f2(n, cache);  
    }  
  
    //改进版本  
    //定义方法  斐波那契数列: 0,1、1、2、3、5、8、13、21、34……  
    public static int f2(int n, int[] cache) {  
        //从第三项开始 每一项的值为前两项之和  数学定义 F(0) = 0,F(1) = 1, F(n) = F(n - 1) + F(n - 2)(n ≥ 2,n ∈ N*)。  
        //TODO 已经初始化了前两项  
        if (cache[n] != -1) {  
            return cache[n];  
        }  
        cache[n] = f2(n - 1, cache) + f2(n - 2, cache);  
        return cache[n];  
    }  
}


6 递归常见案例:

递归二分查找:

//递归查找值
public staic int binarySearch(int[] arr, int target, int i, int j){
	if (i > j){
		return -1; 递归调用到i > j的时候说明没有找到元素 返回-1 
	}
	int m = (i + j) >>> 1;
	if (target < arr[m]){
		binarySearch(arr, targrt, 0, m-1)
	}else if (arr[m] < target){
		binarySearch(arr, targrt, m+1, j)
	}else{
		return m;
	}
	
}

递归冒泡排序法:

双for版本: 具体笔记

递归版本:
private static void bubble_digui(int[] arr, int last) {  
    //递归 每次将最大的值泡在最后面  
    if (last == 0) {  
        return;  //只剩第一个  不需要排序  
    }  
    for (int i = 0; i < last; i++) {  //这里的last是最后一位索引 i+1 不会越界  
        if (arr[i] > arr[i + 1]) {  
            int t = arr[i];  
            arr[i] = arr[i + 1];  
            arr[i + 1] = t;  
        }  
    }  
    //循环结束后  最大值跑到最后一位  
    bubble_digui(arr, last - 1);  
}

//缺点  每次都需要从最后一位往前排序   如果前面是有序的就做了无用功了


递归改进版本[产生临界]:
private static void bubble_digui2(int[] arr, int last) {  
    //递归 每次将最大的值泡在最后面  
    if (last == 0) {  
        return;  //只剩第一个  不需要排序  
    }  
    int linjie = 0;  //定义一个临界边  
    for (int i = 0; i < last; i++) {  //这里的last是最后一位索引 i+1 不会越界  
        if (arr[i] > arr[i + 1]) {  
            int t = arr[i];  
            arr[i] = arr[i + 1];  
            arr[i + 1] = t;  
            linjie = i;  //如果没有更新 说明linjie右边都是有序的  并没发生交换  
        }  
    }  
    /**  
     * TODO  
     *      改进版: 假设一个案例数组 【1,3,5,7,8,9】   
     *      对于这个假设的案例,双for 和 递归 都会比较所有!!!! ===> 不必要的比较 因为本身有序  
     *      对于改进版  如果没有发生交换值--> 不会更新linjie值【说明linjie右边都是有序的】  下次递归 右边有序的不会参与比较  
     */  
    //循环结束后  最大值跑到最后一位  
    bubble_digui2(arr, linjie);  //缺点  每次都需要从最后一位往前   如果前面是有序的就做了无用功了  
}


递归插入排序法:

    //递归实现插入排序  low传递1  因为第一个元素默认不需要排序  
    private static void insertSort_digui(int[] arr, int low){  
        if (low == arr.length){  //防止最后一步会越界  
            return;  
        }  
        int insertvalue = arr[low];  
        int last = low - 1;  //last 表示插入序列的最后一个元素  必须>=0 因为插入元素最远插入到第一个元素  
        while (last >= 0 && arr[last] > insertvalue){  
            //将大数值向后去  
            arr[last+1] = arr[last];  //此处arr[last]  下次比较时候 比插入元素比较小的时候  插入元素的侯选位置  
            last--;  
        }  
        //将插入元素放置last加1的位置  因为 last小于等于insertValue的时候 才会推出循环 last+1 是候选位置  
        arr[last+1] = insertvalue;  
  
  
        //上面一行赋值细节情况:   当low索引的值与前面不需要交换时候 说明low前面正常是有序的【就是last + 1 == low的情况】 就不需要赋值操作  
//        if (last + 1 != low){  
//            arr[last+1] = insertvalue;  
//        }  //没必要添加  
  
        insertSort_digui(arr, low + 1);  
    }

多路递归杨辉三角:
模型: x表示行 y表示列【y=0列 和 x=y的元素都是1】 初始值
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1

	package SF_DiGui;  
	  
	public class duoluDiGui {  
	    public static void main(String[] args) {  
	        print2(5);  
	    }  
	  
	  
	    private static void printSpace(int n, int i){  
	        int num = (n-i-1)*2;  
	        for (int j = 0; j < num;j++){  
	            System.out.print(" ");  
	        }  
	    }  
	  
	  
	  
	    private static void print(int n){  
	        for (int i = 0;i < n; i++){  
	            printSpace(n,i);  
	            for (int j = 0; j <= i;j++){  
	                System.out.printf("%-4d",element(i,j));  
	            }  
	            System.out.println();  
	        }  
	    }  
	  
	    //普通做法
	    private static int element(int x, int y){  //x表示行  y表示列  
	        if (y==0 || x == y){  
	            return 1;  
	        }  
	        return element(x-1,y-1) + element(x-1,y);  //根据坐标系  笔记中有  
	    }  
	      
		//-----------------------------------------------------------------
	    private static void print1(int n){  
	        int[][] taringle = new int[n][];  //初始化n行  
	        for (int i = 0;i < n; i++){    i 表示 索引i行  i+1表示索引i行的元素个数【数组长度】
	            taringle[i] = new int[i+1]; //第i行的元素个数 = 行数i + 1  
	            printSpace(n,i);  
	            for (int j = 0; j <= i;j++){  
	                System.out.printf("%-4d",element1(taringle,i,j));  
	            }  
	            System.out.println();  
	        }  
	    }  
	  
	  
	    //二位数组记忆法
	    private static int element1(int[][] taringle, int x, int y){  
	        if (taringle[x][y] > 0){ //初始值都是0  如果大于1 说明更新过了  
	            return taringle[x][y];  
	        }  
	        if (x == y || y == 0){  
	            taringle[x][y] = 1;  
	            return 1;  
	        }
	        //记忆法:记住那些重复调用的函数返回值,下次判断存不存再即可
	        taringle[x][y] = element1(taringle,x-1,y-1) + element1(taringle,x-1, y);  
	        return taringle[x][y];  
	    }  
	  
	  
	  
	    //-----------------------------------------------------------------
	    //一维数组记忆法改进2  
	    /**
	    *   parame row  上一行数组
	    *   parame i 行号
	    *
	    */
		1 0 0 0 0  i = 0行
		1 1 0 0 0  i = 1行
		1 2 1 0 0  i = 2行
		1 3 3 1 0  i = 3行
		1 4 6 4 1  i = 4行   
		一个特性: 从第二行开始【第二个元素开始】  每个元素 -->  |x,y| = |x-1, y-1| + |x-1, y| 
	    根据这个特性 使用一维数组 记忆数据  减少内存占用 提高时间效率
	    private static void createRow(int[] row: 一维数组, int i){     //方法名:根据上一行生成新的一行
	        if (i == 0){   //TODO 第1行必须进行初始化的  特性是从第二行开始的!!!!
	            row[0] = 1;  //因为无论是哪一行  第一个元素都是1 下面只要不动row[0] 就一直是1
	            return;  
	        }  
	        for (int j = i; j > 0;j--){    //特性是从 第二个元素开始的 j 不能取到0;  我们需要更新第二个及以后的元素即可
	            row[j]: 新复制的 = row[j]: 原来的 + row[j-1];  
	        }  
	    }  
	  
	    private static void print2(int n){  
	        int[] row = new int[n];  //n行有n个元素  初始化一次就行
	        for (int i = 0;i < n; i++){  
	            createRow(row,i); //第i行的元素个数 = 行数i + 1  
	            printSpace(n,i);  
	            for (int j = 0; j <= i;j++){  
	                System.out.printf("%-4d",row[j]);  
	            }  
	            System.out.println();  
	        }  
	    }  
	}

标签:arr,last,递归,int,static,return,解析,含图
From: https://blog.csdn.net/2301_81105667/article/details/144165067

相关文章

  • HttpGet 请求的响应处理:获取和解析数据
    在当今的互联网世界中,数据的获取和解析是构建网络应用的核心。HTTP作为互联网上应用最广泛的协议之一,其GET方法(HttpGet)被广泛用于从服务器请求数据。然而,网络环境的复杂性往往要求我们在请求过程中使用代理服务器来确保安全性和访问控制。本文将详细介绍如何在Java中......
  • LIS中的HL7如何解析?
    HL7(Health Level Severn,健康信息交换第七层协议)组织是一家非盈利性质的国际性组织,主要从事卫生保健环境临床和管理电子数据交换的标准开发。HL7组织参考了国际标准组织ISO(International Standards Organization),采用开放式系统互联OSI (Open System Interconnection)的通......
  • Postman 安装与汉化超详细步骤全解析教程
    下载安装包首先,我们需要获取Postman的安装包。为了方便,链接提供了安装包跟汉化包点击获取postman安装及汉化包为什么要提供安装包跟汉化包?汉化包和postman的版本必须是一致的,如果不一致就会出现汉化后无法打开postman的问题;注意:如果想要汉化的就不能使用最新版本,因为最新版......
  • Java 多线程探秘:核心概念与实用技巧全解析
    1.有三个线程T1,T2,T3,如何保证顺序执行?要确保三个线程T1,T2,和T3按顺序执行,你可以使用多种同步机制。以下是几种常见的方法:Join方法启动T1线程。调用T1.join(),这将使当前线程(假设是主线程)等待直到T1完成。启动T2线程,并调用T2.join()。最后启动T3线程,并......
  • 【HarmonyOS开发】华为商城应用页面实验示例解析(ArkTS实战解析)
    一.实验背景本次项目为华为云鸿蒙应用入门级开发者认证的实验项目,借此来巩固对ArkTS的学习。实验源地址开发者云实验_云实验KooLabs_在线实验_上云实践_云计算实验_AI实验_华为云官方实验平台-华为云 实验目标本实验一共需要完成以下三个部分的任务:本实验将模拟制作......
  • 11.11大促背后的技术保障:SLA与SLO的深度解析与实践案例
    作者:京东物流冯志文背景又到一年的11.11大促日,最近很多团队邮件上下游确认SLA,你是不是还没搞明白服务质量SLA、SLO等概念?本文通过理论知识以及基于SLO告警治理的实践经验分享。详细介绍如何设置SLO、有效的告警泛滥治理、以及如何根据SLO的指标来指导11.11大促及优化服务性能和......
  • 高程解析:大地高、正高、正常高
            高程是指某点沿铅垂方向到基准面的距离,根据基准面的不同,主要分为大地高、正高、正常高,在测绘、地理、建筑等领域有着广泛的应用。(1)大地高       大地高是指某点沿铅垂方向到参考椭球面的距离。       由于地球是一个不规则球体,形状似梨,常用......
  • HarmonyOS Next 密钥管理深度解析
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)中密钥管理相关技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。第一章:密钥管理系统架构一......
  • ESLint CLI 深度解析:配置选项与高效工作流(5)
    CLI命令行工具关于CLI命令行工具,我们在第一节课的时候就用到过一个:eslint--fix.在官网,我们可以看到CLI命令行工具的基本格式为:eslint[options][file|dir|glob]*我们先来看后面的[file|dir|glob]*,这个部分主要是用来指定ESLint应该检查哪些文件:file:用......
  • Esbuild代码调用深度解析:Build API与Transform API的奥秘 (3)
    esbuild提供了丰富的API,允许你在Node.js代码中进行项目打包和代码转换。以下是esbuild的主要API和一些示例用法。项目打包——BuildAPIesbuild的BuildAPI主要用于项目打包,提供了build、buildSync和context三个方法。1.基本配置在项目根目录下创建esb......