数据结构与算法【递归】Java实现

递归

递归是一种解决计算问题的方法,其中解决方案取决于同一类问题的更小子集。

特点:

  • 自己调用自己,如果说每个函数对应着一种解决方案,自己调用自己意味着解决方案是一样的(有规律的)
  • 每次调用,函数处理的数据会较上次缩减(子集),而且最后会缩减至无需继续递归
  • 内层函数调用(子集处理)完成,外层函数才能算调用完成

递归二分查找

具体实现代码如下

    public int f(int[] a, int target, int i, int j) {
        if (i > j) {
            return -1;
        }
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            return f(a, target, i, m - 1);
        } else if (a[m] < target) {
            return f(a, target, m + 1, j);
        } else {
            return m;
        }
    }

递归冒牌排序

未排区域为[0,j],已排区域为[j,数组长度-1]

具体实现代码如下

    public void bubbleSort(int[] a, int j) {
        if (j==0){
            return;
        }
        int temp;
        for (int i = 1; i < j; i++) {
            if (a[i-1] > a[i]) {
                temp = a[i-1];
                a[i-1] = a[i];
                a[i] = temp;
            }
        }
        bubbleSort(a,j-1);
    }

但是这种实现方式存在一定的效率问题。比如说需要排序的数组为[1,2,3,4,5,7,6]。那么经过排序之后,应该为[1,2,3,4,5,6,7]。只需要将6,7交换就好。存在大量无用循环,因此我们可以对冒泡排序进行改进。使用变量x默认为0的位置,并接收上一次交换的下标值。当一次递归x仍然为0,则说明已经没有需要排序的元素了,因此可以直接结束递归。具体实现代码如下

    public static void bubbleSort2(int[] a, int j) {
        if (j == 0) {
            return;
        }
        int temp;
        int x = 0;
        for (int i = 1; i < j; i++) {
            if (a[i - 1] > a[i]) {
                temp = a[i - 1];
                a[i - 1] = a[i];
                a[i] = temp;
                x = i;
            }
        }
        bubbleSort2(a, x);
    }

递归实现插入排序

未排区域为[low,数组长度-1],已排区域为[0,low]

具体实现代码为

    public static void insertSort(int[] a, int low) {
        //结束递归条件
        if (low == a.length) {
            return;
        }
        int i = low - 1;
        int temp = a[low];
        //结束排序条件,当i=-1与找到第一个小于temp元素时
        while (i >= 0 && a[i] > temp) {
            a[i + 1] = a[i];
            i--;
        }
        a[i + 1] = temp;
        insertSort(a, low + 1);
    }

多路递归

上面的递归实现有一个特点就是每个递归函数只包含一个自身的调用,这称之为单路递归。如果每个递归函数例包含多个自身调用,称之为多路递归。

多路递归的经典案例:斐波那契数列

递推关系如下:

简单实现

    public static int f(int n) {
        if (n == 0) {
            return 0;
        }
        if (n == 1) {
            return 1;
        }
        return f(n - 1) + f(n - 2);
    }

斐波那契数列的变种问题

兔子问题

 

  • 第一个月,有一对未成熟的兔子(黑色,注意图中个头较小)
  • 第二个月,它们成熟
  • 第三个月,它们能产下一对新的小兔子(蓝色)
  • 所有兔子遵循相同规律,求第n个月的兔子数

解决思路:设第 n 个月兔子数为 f(n)

  • f(n) = 上个月兔子数 + 新生的小兔子数
  • 而【新生的小兔子数】实际就是【上个月成熟的兔子数】
  • 因为需要一个月兔子就成熟,所以【上个月成熟的兔子数】也就是【上上个月的兔子数】
  • 上个月兔子数,即 f(n-1)
  • 上上个月的兔子数,即 f(n-2)

简单实现

    public static int rabbit(int n){
        if (n==1){
            return 1;
        }
        if (n==2){
            return 1;
        }
        return rabbit(n-1)+rabbit(n-2);
    }

青蛙爬楼梯

  • 楼梯有 n 阶
  • 青蛙要爬到楼顶,可以一次跳一阶,也可以一次跳两阶
  • 只能向上跳,问有多少种跳法

解决思路:因为最后一跳只能为1或是2,那么当从第三个台阶开始时,跳法等于一个台阶的跳法加两个台阶的跳法之和

斐波那契数列的优化

在之前的实现代码中,它的运算流程如下

可以看到,存在许多重复运算。因此我们可以对其进行记忆化(做缓存)

    public static int cache(int n) {
        int[] cache = new int[n + 1];
        Arrays.fill(cache, -1);
        cache[0] = 0;
        cache[1] = 1;
        return f1(cache, n);
    }

    public static int f1(int[] cache, int n) {
        if (cache[n] != -1) {
            return cache[n];
        }
        int x = f1(cache, n - 1);
        int y = f1(cache, n - 2);
        cache[n] = x + y;
        return cache[n];
    }

这种实现方式采用了以空间换取时间。

爆栈问题

每次调用方法时,JVM会给该方法分配一个内存空间,当递归次数过多时内存也会占用过多,当内存分配完毕,还要接着递归时,就会抛出StackOverflowError异常

尾调用

如果函数的最后一步是调用一个函数,那么称为尾调用,例如

function a() {
    return b()
}

下面代码不能叫做尾调用

function a() {
    const c = b()
    return c
}
  • 因为最后一步并非调用函数
function a() {
    return b() + 1
}
  • 最后一步执行的是加法

一些语言的编译器能够对尾调用做优化,例如

function a() {
    // 做前面的事
    return b() 
}

function b() {
    // 做前面的事
    return c()
}

function c() {
    return 1000
}

没优化之前的伪码

function a() {
    return function b() {
        return function c() {
            return 1000
        }
    }
}

优化后伪码如下

a()
b()
c()

相当于平级调用,而不是嵌套调用。之所以可以这样优化,是因为a的函数返回结果就是b的返回结果,那么a的内存可以直接释放。b的返回结果是c的返回结果,那么也可以直接释放b所占用的内存。

但是Java并不支持这种尾调用优化。因此需要避免递归次数过多导致的爆栈问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/145251.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】Ubuntu16.04系统查看已安装的python版本,及其配置

前情提示&#xff1a;我已经在Ubuntu16.04里用源码安装了python3.8.11&#xff0c;Ubuntu16.04系统默认安装2.7.12与3.5.2 1.查看已安装版本 python2 --version #查看python2安装版本 python3 --version #查看python3安装版本 python3.5 --version #查看python3.5安装…

Elasticsearch:ES|QL 快速入门

警告&#xff1a;此功能处于技术预览阶段&#xff0c;可能会在未来版本中更改或删除。 Elastic 将努力解决任何问题&#xff0c;但技术预览版中的功能不受官方 GA 功能的支持 SLA 的约束。目前的最新发行版为 Elastic Stack 8.11。 Elasticsearch 查询语言 (ES|QL) 提供了一种强…

百望云携手华为发布金融信创与数电乐企联合方案 创新金融合规变革

10月27日&#xff0c;北京发布《关于开展全面数字化的电子发票试点工作的公告》&#xff0c;自2023年11月01日起开展数电票试点。千呼万唤始出来&#xff0c;拉开了北京地区企业开展数电票试点的序幕。 百望云作为数电票行业翘楚&#xff0c;电子发票服务平台供应商&#xff0c…

Java学习之路 —— API篇

文章目录 前言Object类2. Objects类3. 包装类4. StringBuilder和StringBuffer5. StringJoiner6. Math7. System8. JDK8开始新增的日期、时间9. Arrays10. Lambda表达式11. 方法引用 前言 其实转语言来说&#xff0c;语法都比较简单&#xff0c;花个三天就会了&#xff0c;但最…

【luckfox】2、添加lcd spi屏st7735和gc9306

前言 本章使用fbtft添加spi lcd st7735/gc9306。 fbtft生成fb0设备&#xff0c;后续通过lvgl可以实现自定义界面绘制。 代码参考 https://gitee.com/openLuat/LuatOS/blob/master/components/lcd/luat_lcd_gc9306x.c 硬件是合宙的&#xff0c;合宙esp32有支持&#xff0c;仿…

Mistral 7B 比Llama 2更好的开源大模型 (二)

Mistral 7B 论文学习 Mistral 7B 论文链接 https://arxiv.org/abs/2310.06825 代码: https://github.com/mistralai/mistral-src 网站: https://mistral.ai/news/announcing-mistral-7b/ 论文摘要 Mistral 7B是一个70亿参数的语言模型,旨在获得卓越的性能和效率。Mistral 7…

外汇天眼:你的交易技术分析,为什么不赚钱?

众所周知&#xff0c;交易圈分为两个派别&#xff0c;一个是基本面分析派&#xff0c;另外一个就是技术分析派。 无论哪个派别都有成功的案例。 今天我们主要来说一下技术分析&#xff0c;市场中&#xff0c;用技术分析来做交易的人有很多&#xff0c;但并不是人人都赚钱&#…

SELF-AUGMENTED MULTI-MODAL FEATURE EMBEDDING

two embeddings f o r g _{org} org​ and f a u g _{aug} aug​ are combined using a gating mechanism 作者未提供代码

RT-Thread系列10——ETH网口设备

文章目录 1. ETH测试第一步&#xff1a;cubemx配置。第二步&#xff1a;board.h配置。第三步&#xff1a;rtthread settings配置第四步&#xff1a;以太网复位引脚设置第五步&#xff1a;修改rtthread源码第六步&#xff1a;修改 cubemx 生成的 main 函数第七步&#xff1a;编译…

救命!这套性能测试的实践痛点和解决方法真的绝了

昨天有同学找我咨询了一个性能测试相关的问题&#xff0c;他说&#xff1a; 他们公司的性能测试实践目前基本成为了形式主义&#xff0c;除了版本迭代时候的单系统单接口压测&#xff0c;没有其他亮点&#xff0c;领导也不重视。想做一些异常测试和高可用测试&#xff0c;体现自…

C++ builder 常见问题汇总

1、CB静态编译设置 2、CB10.3设置经典编译器&#xff08;用于解决10.3弹出代码提示慢&#xff09; 3、CBuilder生成Release版本 &#xff1a; project->Options->CCompiler->Build Configuration 选择 Release project->Options->CLinker中取消Use dynamic RTL…

PP-YOLO: An Effective and Efficient Implementation of Object Detector(2020.8)

文章目录 Abstract1. Introduction先介绍了一堆前人的work自己的workexpect 2. Related Work先介绍别人的work与我们的区别 3.Method3.1. ArchitectureBackboneDetection NeckDetection Head 3.2. Selection of TricksLarger Batch SizeEMADropBlockIoULossIoU AwareGrid Sensi…

python 随机密码生成器

最近在研究PySimpleGUI库&#xff0c;把之前写的一个随机密码生成器改成GUI版本发出来&#xff0c;有兴趣的兄弟们可以拿走。 因为能力有限&#xff0c;目前只能写生成一个随机密码的Gui版本&#xff0c;等我学了更多的内容再慢慢完善。 核心代码很简单&#xff0c;界面也很粗陋…

2023年华为杯数学建模E题——代码复盘(第一问)

2023年华为杯数学建模E题 代码复盘 写在最前面目录问题1a计算时间间隔思路说明代码输出结果 插值求解思路代码输出结果 绘图绘制3D图&#xff08;待修改&#xff09; 问题1b数据预处理思路代码 模型训练思路代码输出结果网格调参代码输出结果 写在最前面 超开心又有点遗憾 结果…

Vue3 watch监视和watchEffect函数

Vue3 中的watch使用效果和Vue2 中配置watch配置项的使用效果是一致的。 使用watch监视之前&#xff0c;需要先对watch进行引入。 import {watch} from vue; 一、监视一个ref对象 以下情况只适用于监视一个ref对象。 watch(监视对象, (newValue, oldValue) > { // 监视操作…

使用清华智谱ChatGLM2大模型搭建本地私有知识库

首先放上该方案项目的git地址&#xff1a;https://github.com/chatchat-space/Langchain-Chatchat 以下是我的搭建和踩坑经验记录 一、环境准备 1、python安装 在环境中安装python&#xff0c;我安装的是3.9版本的python&#xff0c;官方要求的是Python 3.8 - 3.10 版本。不知…

Java学习之路 —— Day1(环境配置、变量)

文章目录 前言1. 搭建Java开发环境1.1 下载java1.2 JDK组成1.3 使用idea开发 2. java基本语法2.1 变量类型2.2 Scanner输入2.3 随机数2.4 数组 前言 已经好久没有写博客了&#xff0c;打开这个网站有一种熟悉又陌生的感觉。 前段时间一直在准备秋招&#xff0c;现在也告一段落…

【C++代码】最接近的三数之和,括号生成,合并两个有序链表,合并 K 个升序链表

题目&#xff1a;最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀&#xff0c;返回空字符串 ""。 class Solution { public:string longestCommonPrefix(vector<string>& strs) {string res"";int index 0; f…

专题知识点-二叉树-(非常有意义的一篇文章)

这里写目录标题 二叉树的基础知识知识点一(二叉树性质 )树与二叉树的相互转换二叉树的遍历层次优先遍历树的深度和广度优先遍历中序线索二叉树二叉树相关遍历代码顺序存储和链式存储二叉树的遍历二叉树的相关例题左右两边表达式求值求树的深度找数找第k个数二叉树非递归遍历代码…

Swift 警惕“隐式异步(implicitly asynchronous)”方法的执行陷阱

概览 actor 是 Swift 5.5 中一个“不可思议”的新类型&#xff0c;可以把它看做成一个数据同步器。actor 中所有属性和方法都会被自动“串行”&#xff08;serializes&#xff09;访问和执行&#xff0c;从而有效避免了数据竞争的发生。 不过&#xff0c;在一些微妙的情境下使…