递归算法/斐波那契数列

news2025/1/16 8:20:53

目录

递归

直接递归

间接递归

思想沿用

斐波那契数列


图片来源网络,侵权联系可删

递归

递归(Recursion)是一种编程技术,其中函数或方法直接或间接地调用自身。递归通常用于解决可以分解为更小、更简单的子问题的问题。递归的基本思想是将大问题分解为小问题,然后解决小问题,最后通过组合小问题的解来得到大问题的解。

递归有两种主要的形式:直接递归和间接递归。

直接递归

  1. 直接递归:函数直接调用自身。
/**
 * 计算阶乘
 */
public class Factorial {

    /**
     * 递归实现阶乘
     *
     * @param n
     * @return
     */
    public static int factorial(int n) {
        if (n == 0) {
            return 1;
        } else {
            return n * factorial(n - 1);
        }
    }

    /**
     * 普通实现
     *
     * @param n
     * @return
     */
    public static int factorialTwo(int n) {
        if (n == 0) {
            return 1;
        }
        int ret = 1;
        for (int j = n; j >= 1; j--) {
            ret *= j;
        }
        return ret;
    }

    public static void main(String[] args) {
        System.out.println(factorial(5));  // 输出: 120
        System.out.println(factorialTwo(5));  // 输出: 120
    }
}

间接递归

public class IndirectRecursionFactorial {
  
    // 主函数,用于计算阶乘  
    public static long factorial(int n) {  
        if (n < 0) {  
            throw new IllegalArgumentException("Factorial is not defined for negative numbers.");  
        } else if (n == 0 || n == 1) {  
            return 1;  
        } else {  
            // 调用辅助函数来计算阶乘  
            return factorialHelper(n, 1);  
        }  
    }  
  
    // 辅助函数,用于递归计算阶乘  
    private static long factorialHelper(int n, long result) {  
        if (n == 1) {  
            return result;  
        } else {  
            // 递归调用自身,将n减1,并将当前数与之前的结果相乘  
            return factorialHelper(n - 1, n * result);  
        }  
    }  
  
    public static void main(String[] args) {  
        // 测试代码,计算5的阶乘  
        long factorialOf5 = factorial(5);  
        System.out.println(factorialOf5);  
    }  
}

注:间接递归更是可以作为记忆化(也称为动态规划)来更优秀的实现很多,在辅助函数中处理记录已经计算过的数值,用于下次递归不需要再进行代码逻辑处理

思想沿用

有没有发现很多算法思想都是沿用的递归。递归思想的核心是将一个大问题或复杂任务分解为若干个小问题或子任务,然后逐个解决这些小问题或子任务,最终将它们的解决方案组合起来,得到原问题的解。这种分解和组合的过程通常通过函数或方法自身的调用来实现,即方法或函数直接或间接地调用自身。递归思想在很多算法和数据结构中都有应用,例如树的遍历、图的搜索等。

  1. 排序和搜索算法:递归常用于实现排序和搜索算法。例如,快速排序和归并排序都是基于递归的排序算法。它们通过将问题分解为更小的问题来排序数据,然后再将结果合并起来。此外,二分搜索也使用了递归思想。

  2. 树的遍历:在数据结构如树和图的遍历中,递归是一种非常自然和有效的解决方案。例如,二叉树的前序、中序和后序遍历,以及图的深度优先搜索(DFS)和广度优先搜索(BFS,尽管BFS通常使用队列实现而非递归)都可以使用递归来实现。

  3. 分治算法:分治算法是一种典型的递归思想的应用,它将一个大问题划分为若干个相对独立的子问题,递归地解决这些子问题,然后将子问题的解合并起来,得到原问题的解。除了快速排序和归并排序,其他如棋盘覆盖问题、旅行商问题等也可以通过分治算法和递归来解决。

  4. 动态规划:动态规划问题通常也可以使用递归来表达其状态转移方程。然而,为了避免重复计算,通常会结合记忆化搜索或迭代的方式来优化递归解法。递归为动态规划提供了一种自然的建模方式。

  5. 数学归纳法:递归与数学归纳法的思想密切相关。当问题的解决方案基于其更小规模的情况时,递归是一种自然的选择。例如,斐波那契数列和阶乘问题都可以通过数学归纳法建模,并用递归解决。

  6. 游戏开发和计算机图形学:在游戏开发和计算机图形学领域,递归也常用于解决一些复杂的路径查找和图形渲染问题。例如,迷宫寻路算法就经常采用递归实现。

  7. 表达式求值:在编译器和解释器设计中,递归常用于解析和求值复杂的数学表达式或编程语言的语法结构。

注:虽然递归思想在许多情况下都很有用,但它也可能导致性能问题,特别是当递归深度很大时,可能会导致栈溢出。

斐波那契数列

既然说到了递归,必然想到了斐波那契数列,斐波那契数列是一个经典的递归问题,其定义本身就是递归的:每个数字是前两个数字的和。

斐波那契数列是这样定义的:

F(0) = 0
F(1) = 1
F(n) = F(n-1) + F(n-2),对于所有n > 1

这个定义中的 F(n) = F(n-1) + F(n-2) 是一个递归公式,它表示第 n 个斐波那契数是通过前两个斐波那契数计算得到的。这种自我引用的特性正是递归的核心。

使用递归方法来实现斐波那契数列是非常直观的。

/**
 * 斐波那契
 * 斐波那契数列(Fibonacci sequence),又称黄金分割数列,是由意大利数学家列昂纳多·斐波那契提出的。
 * 这个数列从第三项开始,每一项都等于前两项之和。具体数值为:1、1、2、3、5、8、13、21、34……以此类推。
 *
 * 在数学上,斐波那契数列可以用递推的方式定义:F(1)=1,F(2)=1,F(n)=F(n - 1)+F(n - 2)(n ≥ 3,n ∈ N*)。
 * 这意味着第三项是前两项的和,第四项是第三项和第二项的和,以此类推。
 */
public class MutualRecursion {
    public static int fibonacciA(int n) {  
        if (n <= 1) {  
            return n; // 基本情况,终止条件  
        } else {  
            return fibonacciB(n - 1) + fibonacciB(n - 2); // 调用funcB  
        }  
    }  
  
    public static int fibonacciB(int n) {  
        if (n <= 1) {  
            return n; // 基本情况,终止条件  
        } else {  
            return fibonacciA(n - 1) + fibonacciA(n - 2); // 调用funcA  
        }  
    }  
  
    public static void main(String[] args) {  
        System.out.println(fibonacciA(8)); // 输出斐波那契数列的第5项
    }  

 

这种直接的递归实现方式在计算较大的斐波那契数时效率非常低,因为它会重复计算很多相同的子问题。例如,为了计算 F(5),它会计算 F(4) 和 F(3),而计算 F(4) 时又会计算 F(3) 和 F(2),这样就重复计算了 F(3)。这种重复计算随着 n 的增大而急剧增加,导致算法的时间复杂度呈指数级增长。

为了提高效率,我们可以使用记忆化(也称为动态规划)或迭代方法来避免重复计算。记忆化是通过将已经计算过的子问题的结果存储起来,在需要时直接查找而不是重新计算。迭代方法则是通过循环来逐步计算斐波那契数列的每一项,而不是使用递归调用。

总之,递归是计算斐波那契数列的一种直观方法,但需要注意其效率问题。在实际应用中,我们通常会选择更高效的算法来计算斐波那契数列。

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

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

相关文章

抗D盾是什么,为什么游戏被攻击了需要抗D盾

游戏行业DDoS攻击的主要原因是因为游戏产品生命周期偏短&#xff0c;而DDoS供给成本又不高&#xff0c;只要发起攻击&#xff0c;企业为确保游戏稳定运营而不得不快速做出让步&#xff0c;致使敲诈勒索的成功率相对更高。在遭受DDoS攻击后&#xff0c;游戏公司的日损失甚至多达…

[Flutter3] 记录Dio的简单封装(一)

文章目录 效果使用ResponseEntity类DioManager封装_onResponse / _onDioException 的设计Response的处理catch处理 效果 请求成功/失败/异常的日志输出效果 成功: 失败:500 失败:404 网络异常: 使用 举个使用的例子, 在调用 DioManager的时候, 直接通过返回值的状态, 来…

世强硬创获昕感科技授权代理,SiC MOSFET实现超低导通电阻

近日&#xff0c;世强先进&#xff08;深圳&#xff09;科技股份有限公司&#xff08;下称“世强先进”&#xff09;获北京昕感科技有限责任公司&#xff08;下称“昕感科技”&#xff0c;英文名&#xff1a;NEXIC&#xff09;授权代理&#xff0c;为光伏、储能、电网、新能源汽…

【芯片科普】运算放大器用作比较器的注意事项

运算放大器和比较器 比较器和运算放大器电气符号非常相像&#xff0c;都是有反相、同相两个输入端和一个输出端的器件&#xff0c;输出端的输出电压范围一般在供电的轨到轨之间&#xff1b;同时比较器和运算放大器都具有低偏置电压、高增益和高共模抑制比的特点。 图1 运算放…

第十五届蓝桥杯省赛第二场C/C++B组F题【狡兔k窟】题解(AC)

题意分析 有一个 n n n 个点&#xff0c; n − 1 n-1 n−1 条边的无向图&#xff0c;边权均为 1 1 1。 每个点隶属于一个集合&#xff0c;同一个集合的点可以互相传送。 给定 m m m 个询问&#xff0c;求 x , y x, y x,y 的最短距离。 最短路解法 步骤&#xff1a; 建…

4.7 海思SS928开发 - uboot开发 - 自定义分区以及启动方案

4.7 uboot开发 - 自定义分区以及启动方案 ss928 出厂默认的启动方式以及 emmc 默认的分区&#xff0c;不符合需求&#xff0c;考虑自己做一个分区方案以及启动方案。 分区方案 分区表如下&#xff1a; 分区文件系统分区说明fastboot-存放 bootloaderubootenv-存储 uboot 环境…

jenkins修改全局安全配置之后登录错误

教训&#xff08;流泪&#xff09; 事情是这样的&#xff0c;第一次我需要用单点登录集成jenkins&#xff0c;jenkins可以通过插件的方式支持cas协议&#xff0c;我当时也不很懂&#xff0c;经过我学网上的一顿乱配置&#xff0c;jenkis上不去了&#xff0c;虽然这是公司本地环…

Nginx 配置 SSL(HTTPS)详解

Nginx作为一款高性能的HTTP和反向代理服务器&#xff0c;自然支持SSL/TLS加密通信。本文将详细介绍如何在Nginx中配置SSL&#xff0c;实现HTTPS的访问。 随着互联网安全性的日益重要&#xff0c;HTTPS协议逐渐成为网站加密通信的标配。Nginx作为一款高性能的HTTP和反向代理服务…

C语言----枚举

当我们看过了结构体和联合体&#xff0c;那么我们接下来就将学习枚举。这也许对大家又是一个新的知识点。大家不要急&#xff0c;我来给大家简单的总结一下。先看名字&#xff0c;枚举就是一个个列举。这样大家应该比较熟悉吧。如一周有七天。这个肯定要分开列举出来吧&#xf…

LLMs——扩展数据受限的语言模型解决方案

概述 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;大型语言模型的发展一直是研究的热点。这些模型通过增加参数数量和训练数据量来提升性能&#xff0c;但这种增长趋势是否会有一个极限&#xff1f;实际上&#xff0c;研究者们已经注意到&#xff0c;为了有效地…

03-JAVA设计模式-观察者模式

观察者模式 什么是观察者模式 Java中的观察者模式是一种常见的设计模式&#xff0c;它允许对象&#xff08;观察者&#xff09;订阅另一个对象&#xff08;被观察者&#xff09;的状态变化&#xff0c;并在状态变化时自动得到通知。 核心&#xff1a; 观察者模式主要用于1&a…

Python 基础 (Pandas):Pandas 入门

1. 官方文档 API reference — pandas 2.2.2 documentation 2. 准备知识&#xff1a;Pandas 数据结构 Series & DataFrame 2.1 Series 2.1.1 创建 Series 类型数据 一个 Series 对象包含两部分&#xff1a;值序列、标识符序列。可通过 .values (返回 NumPy ndarry 类型…

Swift - 基础语法

文章目录 Swift - 基础语法1. 常量1.1 只能赋值1次1.2 它的值不要求在编译时期确定&#xff0c;但使用之前必须赋值1次1.3 常量、变量在初始化之前&#xff0c;都不能使用 2. 标识符3. 常用数据类型4. 字面量4.1 布尔4.2 字符串4.3 整数4.4 浮点数4.5 数组4.6 字典 5. 类型转换…

【C++】string类的增删改查模拟实现(图例超详细解析!!!)

目录 一、前言 二、string类的模拟实现 ✨前情提要 ✨Member functions —— 成员函数 ⚡构造函数 ⚡拷贝构造函数 ⚡赋值运算符重载 ⚡析构函数 ✨Element access —— 元素访问 ⚡operator[ ] ⚡Iterator —— 迭代器 ✨Capacity —— 容量 ⚡size ⚡capacity ⚡clea…

记录一个Maxwell采集MySQL数据时报安全证书时间不通过的问题

【背景描述】 我的zk&#xff0c;kafka和Maxwell都正常启动了 此时我需要用Maxwell将MySQL的一张表user_info将其全量同步到kafka当中时发生报错&#xff0c;命令如下&#xff1a; [atguiguhadoop102 datas]$ /opt/module/maxwell/bin/maxwell-bootstrap --database gmall --…

Mongodb语法使用说明(含详细示例)

点击下载《Mongodb语法使用说明&#xff08;含详细示例&#xff09;》 1. 前言 MongoDB是一款高性能、开源、面向文档的NoSQL数据库&#xff0c;它使用类似JSON的BSON格式存储数据&#xff0c;提供了灵活的数据模型和强大的查询功能。本文将详细介绍MongoDB数据库的基本增删改…

机器学习-期末复习

本文的内容按照作者的课程考试要求书写&#xff0c;仅供复习参考。&#x1f337;&#x1f337;&#x1f337;欢迎大家指正&#xff01; 机器学习是一种人工智能&#xff08;AI&#xff09;的分支领域&#xff0c;它致力于开发能够通过数据学习和改进的算法和模型。简而言之&…

深入学习Linux中的“文件系统与日志分析”

目录 1.文件系统的组成 1.1inode和block 1.2inode的内容 1.3inode的号码 ​1.4文件存储小结 ​1.5inode大小 1.6inode的特殊作用 2. 链接文件 3.文件恢复 3.1EXT类型文件恢复 3.2磁盘有空间&#xff0c;但是仍然无法写入新文件 3.3恢复XFS类型的文件 3.3.1xfsdump…

面试:JVM内存结构

一、Java代码的运行步骤 一段Java代码先会被反编译为Java字节码&#xff0c;当执行java命令时&#xff0c;JVM虚拟机会被创建出来&#xff0c;并会创建一个main主线程来执行主方法。 二、JVM的内存结构有哪些&#xff1f; 1、方法区&#xff1a;&#xff08;线程共享&#xff…

实验五 Spark SQL编程初级实践

Spark SQL编程初级实践 Spark SQL基本操作 将下列JSON格式数据复制到Linux系统中&#xff0c;并保存命名为employee.json。 { "id":1 , "name":" Ella" , "age":36 } { "id":2, "name":"Bob","a…