数据结构与算法【递归】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并不支持这种尾调用优化。因此需要避免递归次数过多导致的爆栈问题。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机毕业设计选题推荐-体育赛事微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

图像分类:对google/vit-large-patch32-384模型进行微调

背景&#xff1a; 图像分类是很常见的场景&#xff0c;比如日常的物体识别&#xff0c;可很多时候我们还需要根据自己的数据来训练自己的分类&#xff0c;大模型出现以后&#xff0c;我们不需要再重头来训练我们的模型&#xff0c;直接根据已经训练好的大模型进行微调即可&…

Oracle(2-1) Networking Overview

文章目录 一、基础知识1、Network Environ Challenges 网络环境挑战2、Simple Network :2-Tier 简单的两层网络3、Simple to Complex : N-Tier 简单到复杂&#xff1a;N层网络4、Oracle Network Solutions Oracle网络解决方案5、Key Features of Oracle Net Oracle Net的主要功…

JavaWeb篇_09——Tomcat运行过程以及Servlet继承结构

Tomcat运行过程 用户访问localhost:8888/test/helloword.do&#xff0c;请求被发送到Tomcat&#xff0c;被监听8888端口并处理 HTTP/1.1 协议的Connector获得。Connector把该请求交给它所在的Service的Engine来处理&#xff0c;并等待Engine的回应。Engine获得请求localhost/t…

酷柚易汛ERP-购货订单操作指南

1、应用场景 先下购货订单&#xff0c;收货入库后生成购货单。 2、主要操作 2.1 新增购货订单 打开【购货】-【购货订单】新增购货订单。&#xff08;*为必填项&#xff0c;其他为选填&#xff09; ① 录入供应商&#xff1a;点击供应商字段框的 &#xff0c;在弹框中选择供…

买房和租房哪个划算?

目录 1、考虑因素 1. 1费用比较 1.2 资产增值 1.3 税收影响 1.4 灵活性 1.5 贷款利率 1.6 长期计划 1.7 当地市场条件 2、买房计算 2.1等额本息 2.2等额本金 3、租房计算 1、考虑因素 在比较买房和租房哪个更划算时&#xff0c;需要考虑多个因素。以下是一些可以考…

客户下单时如何自动匹配到最近的门店

有些商家有多个门店&#xff0c;当客户下单时&#xff0c;希望能够将客户下的订单分配给最近的门店。下面就具体介绍一下在采云小程中是如何实现的。 首先&#xff0c;为了简便起见&#xff0c;请确定门店高级设置保持着默认设定。因为单独的商品管理模式以及独享的商品信息模…

【milkv】0、duo编译环境搭建

一、开发资料整理 Docker https://hub.docker.com/repository/docker/dreamcmi/cv1800-docker/general GitHub https://github.com/milkv-duo/duo-buildroot-sdk CV181x/CV180x MMF SDK 开发文档汇总 https://developer.sophgo.com/thread/471.html cv181x芯片使用的交叉…

CCF 备忘

一、不错的网站 CCF CCSP 竞赛历年资料 官网 http://118.190.20.162/home.page 二、基础套路 循环输入 数组标记法&#xff08;数组下标-数值 的映射&#xff09; 两个矩阵相乘 map<long long, map<long long, long long> > ans; for(int i1;i<d;i){for(int…

长按事件怎么加定时器

要实现长按事件并加入定时器&#xff0c;你可以结合使用mousedown和mouseup事件&#xff0c;然后在mousedown时启动定时器&#xff0c;在mouseup时停止定时器。以下是一个使用Vue.js的例子&#xff1a; <template><div><p>长按计时器示例: {{ timerValue }}…

【Linux】 ls -l 和 grep

语法:用于显示指定工作目录下之内容 ls [-alrtAFR] [name...]将 /bin 目录以下所有目录及文件详细资料列出: ls -lR /bin将 /usr/local/bin 目录以下所有有关python列出: ls -l /usr/local/bin/ | grep python在使用 ls -l 命令时&#xff0c;第一列的字符表示文件或目录的类…

js 加密解密 cryptojs(对称加密库)

js 加密解密可以使用 crypto-js 这是一个对称加密的库&#xff0c; 可以使用 AES DES 但没有 rsa 等非对称加密的方法 安装方法 npm install crypto-js 它可以进行 MD5 SHA-1 SHA-256 Base64 AES DES 等算法和加密 import crypto from "crypto-js"let md5binary cry…

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

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

C++阶段复习‘‘‘‘总结?【4w字。。。】

文章目录 前言类和对象C类定义和对象定义类成员函数C 类访问修饰符公有&#xff08;public&#xff09;成员私有&#xff08;private&#xff09;成员受保护&#xff08;protected&#xff09;成员 继承中的特点类的构造函数和析构函数 友元函数内联函数this指针指向类的指针类…

缩点+图论路径网络流:1114T4

http://cplusoj.com/d/senior/p/SS231114D 重新梳理一下题目 我们先建图 x → y x\to y x→y&#xff0c;然后对点分类&#xff1a;原串出现点&#xff0c;原串未出现点。 假如我们对一个原串出现点进行了操作&#xff0c;那么它剩余所有出边我们立刻去操作必然没有影响。所…

快速入门安装及使用git与svn的区别常用命令

一、导言 1、什么是svn&#xff1f; SVN是Subversion的简称&#xff0c;是一个集中式版本控制系统。与Git不同&#xff0c;SVN没有分布式的特性。在SVN中&#xff0c;项目的代码仓库位于服务器上&#xff0c;团队成员通过向服务器提交和获取代码来实现版本控制。SVN记录了每个…

数据库实验二

--①查询信息管理系学生的学号和姓名。 --select sno,sname from Student where sdept IS --②查询选修了课程的学生的学号。 --select distinct sc.sno from sc,student --③查询选修了课程号为C001的学生的学号和成绩&#xff0c;并对查询结果按成绩降序排列&#xff0c;如…

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

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

蒙特卡洛树搜索(Monte Carlo Tree Search)揭秘

一. 什么是蒙特卡洛树搜索 蒙特卡洛树搜索(MCTS)是一种启发式搜索算法&#xff0c;一般用在棋牌游戏中&#xff0c;如围棋、西洋棋、象棋、黑白棋、德州扑克等。MCTS与人工神经网络结合&#xff0c;可发挥巨大的作用&#xff0c;典型的例子是2016年的AlphaGo&#xff0c;以4:1…

Elasticsearch:ES|QL 快速入门

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