java递归算法(一)——详解以及几个经典示例

article/2025/10/29 12:39:35

什么是递归

递归就是一个程序或函数在其中定义或说明有之间或者间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个原问题相似的规模较小的问题来求解,递归策略只需要少量的程序就可以描述出解题过程所需要的多次重复计算,大大的减少了程序的代码量,递归的能力在于用有限的语句来定义对象的无限集合,一般来说,递归需要边界条件,递归前进段和递归返回段,当边界条件不满足时,递归前进,当边界条件满足时,递归返回。

递归示例

我这里采用的是一个很常见的问题,也是我在知乎上面看到的

  • 假设你在一个电影院,你想知道自己坐在哪一排,但是前面人很多,你懒得去数了,于是你问前一排的人「你坐在哪一排?」,这样前面的人 (代号 A) 回答你以后,你就知道自己在哪一排了——只要把 A 的答案加一,就是自己所在的排了,不料 A 比你还懒,他也不想数,于是他也问他前面的人 B「你坐在哪一排?」,这样 A 可以用和你一模一样的步骤知道自己所在的排。然后 B 也如法炮制,直到他们这一串人问到了最前面的一排(或者说问到了知道自己是哪一排的人,预示着调用结束),第一排的人告诉问问题的人「我在第一排」,最后大家就都知道自己在哪一排了

递归算法实例

  • 阶乘
    要求给一个数值,计算它的阶乘,例如给的是4 阶乘为432*1
public class DiGui {public static int getFactorial(int n) {if (n >= 0) {if (n == 0) {System.out.println(n + "!=1");return 1;} else {System.out.println(n);int temp = n * getFactorial(n - 1);System.out.println(n + "!=" + temp);return temp;}}return -1;}public static void main(String[] args) {getFactorial(4);}}

输出
在这里插入图片描述
由下面的图形可以知道详细的过程

在这里插入图片描述
getFactorial方法在调用自身的时候,它的参数是4,每次减一,这个方法返回自身,知道减到0,于是方法返回,这样会引发一系列的返回,脱离被放弃的那一层,每当返回时,这个方法把调用它的单数n与其调用的下一层的返回值想乘,注意,在最底层返回之前,实际上是在同一时刻有四个不同的getFactorial方法实例存在,最外层是4,最里面的是1

递归的二分查找

首先二维数组一定是有序的,
在有序的数组array[]中,不断地将中间值(mid)和被查找的值比较,如果被查找的值等于affay[],就返回下标array[mid],否则就像查找的范围缩小一半,如果被查找的小于array【mid】,就继续查找左边得值,如果查找大于array【mid】就向右边查找,直到查找为空,查找结束!
在这里插入图片描述详细代码请查看我的这一篇博客
https://blog.csdn.net/qq_40688338/article/details/84557959

分治算法

当我们求解某些问题,由于这些问题要处理的数据相当多,或求解的方式比较复杂,使得直接求解在时间上相当长,或者直接无法求出,对于这类问题,我们往往把它分成几个子问题,找到求出这个子问题的解法后,再找到合适问题的解法,如果这些子问题还较大,难以解决,我们可以把它再分成介个更小的子问题,以此类推,直到找到解法为止,这就是分治解法的基本思想。
上面所说的递归的二分查找就是一个分治算法的经典例子,分治算法常常是一个方法,在这个方法中含有两个对自身的递归调用,分别对应于问题的两个部分,
二分查找中,将查找范围分成比查找值大的一部分和比查找值较小的一部分,每次递归只有一部分执行。

汉诺塔问题

汉诺塔问题是由很多放置在三个塔座上的盘子组成的一个古老的难题,如下图所示,所有的盘子的直径是不同的。并且盘子中央都有一个洞使得它刚好可以放在塔座上,所有的盘子刚开始都是在a座上,这个难题的目标是将左右的盘子都从塔座a,移到塔座c上,每次只可以移动一个盘子,并且任何一个盘子都不可以放置在比它小的盘子上,
在这里插入图片描述这个问题可以先从简单的方面想,然后一步一步出发,假设有2个盘子,盘子的大小我按照阿拉伯数字命名。从小到大,如果a上面有两个盘子,分别是1,2那么我们只需要把1的盘子移到b上面,然后把2的盘子移到c上面,最后把b上面的盘子1移动到c上面就可以了,这样两个盘子的问题就解决了,
如果是三个盘子呢?我们一样的来命名1,2,3,假设先把1的盘子移动到c的上面,然后把2的盘子移动到b上面,这样目前就是a上面的是3,b上面的是2,c上面的是1,然后将c上面的盘子移动到b上面,继续把a的盘子移动到c上面,这样的话,目前就是b上面有1,2,c上面的有3,现在答案已经很清楚了,将b上面的盘子移动到a上面,然后第二个盘子移动到c上面,最后a的盘子移动到c上面,这样问题就解决了,
但是如果有四个,五个,n个盘子呢?这个时候递归的思想就很好的解决这样的问题了,当只有两个盘子的时候,我们只需要将b塔座作为中介,将盘子1放到中介b上面,然后将盘子2放到c上面,最后将b上面的盘子1移动到c盘就可以了

所以无论多少盘子,我们都将其看做只有两个盘子,假设n个盘子在a的上面,我们将其看做只有两个盘子,只有(n-1)和n这两个盘子,

  • 先将a上面的n-1的哪一个盘子放到塔座b上面,然后将第n的盘子放到目标塔上面,
  • 然后a的上面为空,看做中间塔,b上面的有n-1个盘子,将第n-2以下的盘子看成一个盘子,放到中间a塔上面,然后将第n-1的盘子放到c上面,
  • 这是发现a上面有n-2个盘子,b上面为空,按照上面的方式以此类推,直到全部放到冰箱里面

简单的来说

  1. 从初始塔a上移动到包含n-1个盘子到c上面
  2. 将a上面剩下的一个盘子,放到c上面
  3. 然后假设b上面有n-1个盘子,然后将它看成为n继续将看成n的盘子中间的n-1个盘子放到a上面
  4. 将b上面剩下的那个盘子放到c上面。
 public static void main(String[] args) {
//        getFactorial(4);move(4,"A","B","C");}/*** 汉诺塔问题** @param dish 盘子个数(也表示名称)* @param from 初始塔座* @param temp 中介塔座* @param to   目标塔座*/public static void move(int dish, String from, String temp, String to) {if (dish == 1) {//圆盘只有一个的时候 将其从a移动到cSystem.out.println("将盘子" + dish + "从塔座" + from + "移动到目标塔座" + to);}else {move(dish-1,from,to,temp);//a为初始塔座,b为目标塔座,c为中介塔座System.out.println("将盘子"+dish+"从塔座"+from+"移动到目标"+to);//把a上面的最下面的一个盘子移到c上面move(dish-1,temp,from,to);//b为初始塔座,c为目标塔座,a为中介塔座}}

输出
在这里插入图片描述

归并排序

归并排序算法的中心是归并两个已经有序的数组,归并两个有序的数组a和b,就生成了第三个有序的数组c,数组就是包含数组a和数组b的所有数据项,同时该算法采用经典的分治策略

在这里插入图片描述
未使用递归算法

    public static void main(String[] args) {
//        getFactorial(4);
//        move(4,"A","B","C");int[] array = {11, 22, 33, 44, 55, 66, 77, 88, 99, 100, 104};int[] arrayB = {1, 21, 41, 51, 61, 71, 81, 91};int[] arrayC = new int[19];merge(array,arrayB,arrayC);display(arrayC);}/*** @param arrayA 数组a* @param arrayB 数组B* @param arrayC 数组C*/public static void merge(int[] arrayA,int[] arrayB,int[] arrayC) {int a = 0;int b = 0;int c = 0;while (a < arrayA.length && b < arrayB.length) {//当a和b都有数据数才执行if (arrayA[a] < arrayB[b]) {//当a的数小于b的数时arrayC[c++] = arrayA[a++];//将a的数添加到c中并且下标加1} else {arrayC[c++] = arrayB[b++];//将b中的数添加到c中并且下标加一}}//走到这一步的时候要么是a中没有数或者是b中没有数while (a < arrayA.length) {arrayC[c++] = arrayA[a++];//如果A中存在则将剩下的数添加到c中}while (b < arrayB.length) {arrayC[c++] = arrayA[b++];//如果b中的数存在则先加到c中}}/*** 排序*/public static void display(int[] array) {for (int j = 0; j < array.length; j++) {System.out.print(array[j] + ",");}}

输出
在这里插入图片描述
详细的步骤我在代码上面已经写下来了

递归排序
  • 先将数组分成两半
  • 再把每一半分成两个1/4,
  • 继续把1/4分解成1/8依次类推
  • 直到分割成一个一个的数组,再把这些数据归并到一起直到有序
    在这里插入图片描述
public static void main(String[] args) {int[] arr = {12, 41, 2, 3, 6, 54, 15, 21, 41, 85, 94, 12, 46};arr = merSort(arr, 0, arr.length - 1);System.out.println(Arrays.toString(arr));}public static int[] merSort(int[] arr, int start, int last) {if (last > start) {//也可以是(start+last)/2,这样写是为了防止数组长度很大造成两者相加超过int范围,导致溢出int mid = start + (last - start) / 2;merSort(arr, start, mid);//左边数组的排序merSort(arr, last, mid);//右边数组的排序merge(arr, start, mid, last);}return arr;}public static void merge(int[] arr, int start, int mid, int last) {int[] temp = new int[last - start + 1];//临时定义的数组int i = start;//定义左边数组的下标int j = mid + 1;//定义右边数组的下标int k = 0;while (i <= mid && j <= last) {if (arr[i] < arr[j]) {temp[k++] = arr[i++];} else {temp[k++] = arr[j++];}}//            把左边的数移动到新的数组while (i <= mid) {temp[k++] = arr[i++];}
//        把右边的数移动到新的数组中while (j <= last) {temp[k++] = arr[j++];}
//        把新数组中的数覆盖到arr中for (int a = 0; a < temp.length; a++) {arr[a + start] = temp[a];}}

输出在这里插入图片描述

归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(NlogN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(NlogN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。


http://chatgpt.dhexx.cn/article/ZQ7gQqlp.shtml

相关文章

Java 递归算法

一、概述&#xff1a; Java递归&#xff1a;简单说就是函数自身直接或间接调用函数的本身。 二、应用场景&#xff1a; 若&#xff1a;一个功能在被重复使用&#xff0c;并每次使用时&#xff0c;参与运算的结果和上一次调用有关&#xff0c;这时就可以使用递归来解决这个问题…

递归与递归算法实例(java实现)

一、递归介绍 递归算法&#xff08;英语&#xff1a;recursion algorithm&#xff09;在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法。绝大 多数编程语言支持函数的自调用&#xff0c;在这些语言中函数可以通过调用自身来进行递归。 定义&#xff1…

Java的递归算法

递归算法设计的基本思想是&#xff1a;对于一个复杂的问题&#xff0c;把原问题分解为若干个相对简单类同的子问题&#xff0c;继续下去直到子问题简单到能够直接求解&#xff0c;也就是说到了递推的出口&#xff0c;这样原问题就有递推得解。 关键要抓住的是&#xff1a; &…

java递归算法实现

Coding多了&#xff0c;递归算法是非常常见的&#xff0c;最近我一直在做树形结构的封装&#xff0c;所以更加的离不开递归算法。所以今天就简单说一下这个递归算法&#xff0c;用java实现一个非常经典的递归实例。 递归算法&#xff0c;其实说白了&#xff0c;就是程序的自身调…

【Java】递归算法

文章目录 什么是递归&#xff1f;递归求阶乘递归求解斐波那契数列猴子吃桃问题 什么是递归&#xff1f; 程序 调用自身 的编程技巧成为 递归&#xff08;recursion&#xff09;。 递归算法是一种直接或间接调用、定义自身的函数或方法的算法&#xff0c;也就是调用自身。 递归…

Java递归算法

递归在程序语言中就是方法本身自己调用自己&#xff0c;而递归思想是算法的重要思想之一&#xff0c;就是利用递归来实现解决问题的算法。 递归也分为直接递归和间接递归。 那么什么叫直接递归什么又叫间接递归呢&#xff1f; //直接递归调用 function(){...function();... …

散布矩阵(scatter_matrix)及相关系数(correlation coefficients)实例分析

在进行机器学习建模之前&#xff0c;需要对数据进行分析&#xff0c;判断各特征(属性&#xff0c;维度)的数据分布及其之间的关系成为十分必要的环节&#xff0c;本文利用Pandas和Numpy的散布矩阵函数及相关系数函数对数据集特征及其关系进行实例分析。 散布矩阵(scatter_matri…

Probability And Statistics——CorrelationsCovariance

Skew&#xff08;偏度&#xff09; 在概率论和统计学中&#xff0c;偏度衡量实数随机变量概率分布的不对称性。偏度的值可以为正&#xff0c;可以为负或者甚至是无法定义。在数量上&#xff0c;偏度为负&#xff08;负偏态&#xff09;就意味着在概率密度函数左侧的尾部比右侧的…

structural covariance network

structural covariance network 结构协方差网络 结构协方差网络是一个较老的概念&#xff0c;只是近年受到了一定的重视。 大佬 Aaron Alexander-Bloch 在2013年通过一篇综述描述了这种结构协方差网络的应用意义及前景。 既往一般是在bold信号和fiber tracking建立连接&#xf…

_variant_t、CComVariant与COleVariant、CDBVariant

目前计算机语言多种多样&#xff0c;如C、Java、Basic、Pascal等&#xff0c;此外还有JavaScript、VBScript、ActionScript等脚本语言&#xff0c;它们各自维护自己的数据类型&#xff0c;当使用C这样强类型的语言来读取数据库或者与其他语言之间来交换数据时&#xff0c;它很有…

Partial correlation coefficient

利用PYTHON计算偏相关系数&#xff08;Partial correlation coefficient) 在统计学中&#xff0c;我们经常使用皮尔逊相关系数来衡量两个变量之间的线性关系。然而&#xff0c;有时我们感兴趣的是理解两个变量之间的关系&#xff0c;同时控制第三个变量。 例如&#xff0c;假设…

Multilevel Cooperative Coevolution for Large Scale Optimization

0、论文背景 本文在CCEA_G的基础上&#xff0c;提出了MLCC框架。在MLCC中&#xff0c;基于不同组大小的随机分组策略构造了一组问题分解器。演化过程分为若干个循环&#xff0c;在每个周期开始时&#xff0c;MLCC使用自适应机制根据其历史性能选择分解器。由于不同的组大小捕获…

mean value coordinates(均值重心坐标)定义及证明

欢迎关注更多精彩 关注我&#xff0c;学习常用算法与数据结构&#xff0c;一题多解&#xff0c;降维打击。 在图形学中对于物体的描述往往是离散&#xff0c;但是在具体展示过程中我们又希望是连续。线性插值是解决离散与连续的常用手段。 三角形中的插值点击前往凸四边形中的…

numpy中的convolve的理解

写在前面 浏览更多内容&#xff0c;可访问&#xff1a;http://www.growai.cn 欢迎您关注作者知乎&#xff1a;ML与DL成长之路 推荐关注公众号&#xff1a;AI成长社&#xff0c;ML与DL的成长圣地。 函数 numpy.convolve(a, v, mode‘full’)&#xff0c;这是numpy函数中的卷…

Clustering Coefficient

Define Clustering Coefficient&#xff1a;聚类系数 Clustering Coefficient measures the degree to which nodes in a network tend to cluster or form triangles. ——聚类系数衡量网络中节点倾向于聚类或形成三角形的程度 Triadic Closure 三元闭包 The tendency of…

covariate(covariate是控制变量吗)

如何用STATA对连续性变量进行meta回归分析 在stata中有个metareg命令&#xff0c;好像可以对连续变量进行回归分析。 附件中是一篇pdf文档&#xff0c;主要介绍stata中关于meta分析的命令。跟大家分享一下。 里面在提到metareg命令时&#xff0c;列举了以下三个列子&#xff1a…

协方差矩阵简介(Covariance Matrix)

协方差矩阵定义 首先我们要明白&#xff0c;协方差实际是在概率论和统计学中用于衡量两个变量的总体误差,当然方差是协方差的一种特殊情况&#xff0c;即当两个变量是相同情况。它表示的是两个变量的总体的误差&#xff0c;这与只表示一个变量误差的方差不同。如果两个变量的变…

covariance matrix

协方差的定义 对于一般的分布&#xff0c;直接代入E(X)之类的就可以计算出来了&#xff0c;但真给你一个具体数值的分布&#xff0c;要计算协方差矩阵&#xff0c;根据这个公式来计算&#xff0c;还真不容易反应过来。这里用一个例子说明协方差矩阵是怎么计算出来的吧。 记住&…

经典排序算法——堆排序

对于一个int数组&#xff0c;请编写一个堆排序算法&#xff0c;对数组元素排序。 给定一个int数组A及数组的大小n&#xff0c;请返回排序后的数组。 测试样例&#xff1a; [1,2,3,5,2,3],6 [1,2,2,3,3,5] class HeapSort { public:int* heapSort(int* A, int n) {BuildMaxHeap(…

堆排序算法原理及c++实现

文章目录 准备知识MAX-HEAPIFY过程建堆堆排序算法总结 准备知识 堆的结构可以分为最大堆和最小堆&#xff0c;是一个完全二叉树&#xff0c;而堆排序是根据堆的这种数据结构设计的一种排序。 所谓完全二叉树即叶节点只能出现在最下层和次下层&#xff0c;并且最下面一层的结点…