JS算法之递归

news2024/11/24 0:07:52

含义

        递归函数是指能够直接或间接调用自身的方法或函数。

// 直接
function do() {
    do();
}

// 间接
function do() {
    do2();
}
function do2() {
    do()
}

        每个递归函数必须有基线条件(即停止点,一个不再递归调用的条件。)否则将无限递归下去。 因此有一句编程的名言是:“要理解递归,首先要理解递归”。

function understandRecursion(doIunderstandRecursion) {
  const recursionAnswer = confirm('Do you understand recursion?'); // function logic
  if (recursionAnswer === true) { // base case or stop point
    return true;
  }
  understandRecursion(recursionAnswer); // recursive call
}

例子

        迭代阶乘便是迭代函数应用的一个很好的例子。

        n!=n * (n-1) * (n-2) ... * 1

function factorial(n) {
    // 基线条件
    if (n  <= 1) {
        return 1
    }
   return n * factorial(n-1)
}

栈的顺序 

        理解递归,需要理解递归时函数执行的调用栈顺序。

        当我们执行factorial(3)的时候:

        执行步骤为:factorial(3) => 3 *  factorial(2) => 2 * factorial(1) 

        此时函数的执行栈完毕,开始弹出调用栈

         factorial(1)  => factorial(2) => factorial(3)

        我们可以通过浏览器的开发者工具进行观察:

         可以看到我们断点的位置在于n为1的时候。此时调用栈里有三个factorial函数。

      

         继续往下走,此时n=2。此时剩下两个factorial函数。n=1的factionrial函数已经回调完毕(返回1)。

         回调factionrial(1)

Js调用栈大小限制

        如果忘记加上基线条件,递归函数并不会无限地执行下去。当调用栈堆叠到一定限度。浏览器就会抛出错误。也就是所谓的栈溢出错误。

        这个限度是由浏览器自身进行限制的。我们可以通过函数进行测试。

let i = 0;
function recursiveFn() {
  i++;
  recursiveFn();
}

try {
  recursiveFn();
} catch (ex) {
  console.log('i = ' + i + ' error: ' + ex);
}

     Edge超限次数为13903 次

        这个数值根据操作系统和浏览器不同,会有差异。

        ES6有尾调用优化。也就是说如果函数内的最后一个操作是调用函数。会通过“跳转指令”而不是“子程序调用”来控制。也就是说,在ES6中,递归函数可能不受栈溢出限制。因此,具有停止递归的基线条件很重要。

解决斐波那契数列

        斐波那契数列是一个由0、1、1、2、3、5、8、13、21、34等数组成的序列。

         上图是直观上的规律。而抽象出计算机数学规律为:

  •         数列(组)的下标0对应0
  •         数列下标1对应1
  •         数列下标n(n>1)对应下标(n-1)值和下标(n-2)值的和。即value(n) = value(n-1) + value(n-2)

        通过数学规律我们可以发现,只要我们特别处理value(0)和value(1)的返回值。其他的都可以交给迭代函数去累加处理。

        为了减少迭代次数,我们再优化一下规律:

  •         数列(组)的下标0对应0
  •         数列下标1对应1
  •         数列下标2对应1
  •         数列下标n(n>2)对应下标(n-1)值和下标(n-2)值的和。即value(n) = value(n-1) + value(n-2)
function fibonacci(n) {
    if (n===0) {return 0}
    if (n<=2)  {return 1}
    return fibonacci(n-1) + fibonacci(n-2)
}

         调用顺序如图。从左树到右树依次遍历过去。

        fibonacci(5) -> fibonacci(4) -> fibonacci(3) -> fibonacci(2) -> fibonacci(1) ->弹出调用栈到fibonacci(3) -> fibonacci(2) -> f弹出调用栈到fibonacci(4) -> ibonacci(3) -> fibonacci(2) -> fibonacci(1)

记忆斐波那契数列

        记忆化是一种保存前一个结果的值的优化技术。类似于缓存。比如上面的fibonacci(5)里,fibonacci(3)被计算了两次。若将它结果储存下来,便可以少计算一次了。

function fibonacciMemory(n) {
    const memoryResult = [0,1,1];
    const fibonacci = (n) => {
        if (memoryResult[n] != null) return memoryResult[n];
        return memoryResult[n] = fibonacci(n-1) + fibonacci(n-2)
    }
    return fibonacci(n)
}

用迭代去实现

export function fibonacciIterative(n) {
  if (n < 1) { return 0; }
  let fibNMinus2 = 0;
  let fibNMinus1 = 1;
  let fibN = n;
  for (let i = 2; i <= n; i++) {
    fibN = fibNMinus1 + fibNMinus2;
    fibNMinus2 = fibNMinus1;
    fibNMinus1 = fibN;
  }
  return fibN;
}

 

迭代递归性能对比

        迭代的版本比递归的版本快很多,所以这表示递归更慢。但是,再看看三个不同版本的归版本更容易理解,需要的代码通常也更少。另外,对一些算法来说,迭代的解法可能不且有了尾调用优化,递归的多余消耗甚至可能被消除。
        所以,我们经常使用递归,因为用它来解决问题会更简单

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

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

相关文章

每天一个电商API分享:淘宝/天猫获取商品销量详情 API(月销总销)

淘宝/天猫获取商品销量详情API&#xff08;月销总销&#xff09;是一种用于获取电商平台上商品销量数据的接口。通过这个API&#xff0c;用户可以方便地获取到商品的月销量以及总销量等详细信息&#xff0c;快速了解商品的销售情况。 随着电商行业的快速发展&#xff0c;不少卖…

pytest study

pytest 测试用例的识别与运行 测试文件&#xff1a;test_*.py 和 *_test.py 以test开头或结尾的文件 测试用例&#xff1a;Test*类包含的所有 test_*的方法&#xff08;测试类不能带有__init__方法&#xff09;&#xff0c; 不在class中的所有test_*的方法 def func(x):r…

RunnerGo性能测试怎么做?

性能测试—计划管理 新建计划&#xff1a; 在左侧导航栏中&#xff0c;选择“性能测试”&#xff0c;点击“计划管理”进入计划管理界面&#xff0c;点击右上角新建计划来新建测试计划。任务类型选择后不可再更改。定时模式下, 该计划内最多只能创建一个场景。 普通任务&…

如何往MySQL中插入100万条数据?

需求 现在有一个 数据量 为100万的数据样本 100w_data.sql 其数据格式如下&#xff0c;截取最后十条数据 999991,XxGdnLZObA999991,XxGdnLZObA,XxGdnLZObA,2020-3-18,1 999992,TBBchSKobC999992,TBBchSKobC,TBBchSKobC,2020-9-8,2 999993,rfwgLkYhUz999993,rfwgLkYhUz,rfwgLk…

APISIX 安全评估

背景 有大佬已经对 [apisix攻击面](https://ricterz.me/posts/2021-07-05-apache-apisix-attack- surface-research.txt)做过总结。 本文记录一下自己之前的评估过程。 分析过程 评估哪些模块&#xff1f; 首先我需要知道要评估啥&#xff0c;就像搞渗透时&#xff0c;我得…

【三维重建】【深度学习】Windows10下NeRS官方代码Pytorch实现

【三维重建】【深度学习】Windows10下NeRS官方代码Pytorch实现 提示:最近开始在【三维重建】方面进行研究,记录相关知识点,分享学习中遇到的问题已经解决的方法。 文章目录 【三维重建】【深度学习】Windows10下NeRS官方代码Pytorch实现前言NeRS模型运行下载源码并安装环境安装…

体制内裸辞,她用云端地球实现了自己的乡村梦

追逐田园的“诗与远方” “我最初的梦想&#xff0c;就是有一个亲手打造的、能装进个人喜好的小院子。”为完成自己的梦想&#xff0c;吕春萍毅然放弃了体制内的工作&#xff0c;来到秦岭脚下的桥南镇曹峪村&#xff0c;践行自己的“乡村梦”。 起初&#xff0c;吕春萍做了五…

「开源项目」开源企业级问答系统-Danswer

danswer 基本介绍 开源企业级问答系统&#xff0c;可以对内部文档进行自然语言提问&#xff0c;并返回可靠的答案、引用和参考资料&#xff0c;可以连接到多种常见工具&#xff0c;如Slack、GitHub和Confluence。 在线预览 暂无在线预览地址&#xff0c;不过可以自行部署使用…

【error】svn 清理以下路径失败 原始内容不存在

前言 目前我们这边的内网代码是通过 TortoiseSVN 进行版本管理的&#xff0c;平时用着也挺好的&#xff0c;没碰到什么大问题。 但是&#xff0c;今天碰到了一个比较棘手的问题&#xff0c;在这里做一下记录&#xff0c;以方便自己和有需要的朋友在之后碰到该类问题时有个参考…

[php-cos]ThinkPHP项目集成腾讯云储存对象COS

Cos技术文档 1、安装phpSdk 通过composer的方式安装。 1.1 在composer.json中添加 qcloud/cos-sdk-v5: >2.0 "require": {"php": ">7.2.5","topthink/framework": "^6.1.0","topthink/think-orm": "…

为什么中小企业数字化转型这么难?_光点科技

随着科技的飞速发展和数字化时代的到来&#xff0c;数字化转型已成为现代企业发展的必然趋势。大型企业普遍拥有雄厚的资源和资金&#xff0c;能够较为顺利地进行数字化转型。然而&#xff0c;对于中小企业来说&#xff0c;数字化转型却面临着诸多挑战和困难。 资金限制&#x…

5个步骤完成Linux 搭建Jdk1.8环境

1&#xff1a;首先&#xff0c;在Linux系统中创建一个目录&#xff0c;用于存放JDK文件。可以选择在/opt目录下创建一个新的文件夹&#xff0c;例如/opt/jdk。 sudo mkdir /opt/jdk 2&#xff1a;将下载的jdk-8u381-linux-x64.tar.gz文件复制到新创建的目录中。 sudo cp jdk…

如何理解token?

token在项目中的大概流程&#xff1a; 1.客户端使用用户名和密码请求登录 2.服务端收到请求&#xff0c;验证用户名和密码 3.验证成功后&#xff0c;服务端会生成一个token&#xff0c;然后把这个token发送给客户端 4.客户端收到token后把它存储起来&#xff0c;可以放在cookie…

汇编调用C语言定义的全局变量

在threadx移植中&#xff0c;系统的systick通过了宏定义的方式定义&#xff0c;很难对接库函数的时钟频率&#xff0c;不太利于进行维护 所以在C文件中自己定义了一个systick_Div的变量&#xff0c;通过宏定义方式设定systick的时钟频率 在汇编下要加载这个systick分频系数 …

扬州市 自动挡C2 道路驾驶技能考试 电子路要点

先上车把身份证给安全员&#xff0c;验证身份&#xff0c;然后下车逆时针绕车一周&#xff0c;在车头前站立三秒拍照&#xff0c;然后上车 科三基本注意事项 起步不管要不要变道&#xff0c;都必须先打左转向灯&#xff0c;但是也要记得关灯 操作顺序&#xff1a;打左转向灯、…

flutter:BottomNavigationBar和TabBar

区别 BottomNavigationBarr和TabBar都是用于创建导航栏的组件&#xff0c;但它们有一些区别。 位置不同&#xff1a;BottomNavigationBar通常位于屏幕底部&#xff0c;用于主要导航&#xff1b;而TabBar通常位于屏幕顶部或底部&#xff0c;用于切换不同的视图或页面。 样式不…

【2023】java数据结构-时间、空间复杂度分析

1、算法效率 算法效率分析分为两种&#xff1a;第一种是时间效率&#xff0c;第二种是空间效率。时间效率被称为时间复杂度&#xff0c;而空间效率被称作空间复杂度。 时间复杂度主要衡量的是一个算法的运行速度&#xff0c;而空间复杂度主要衡量一个算法所需要的额外空间 2、…

基于Flask+Mongodb的网络文章系统

在这个软件&#xff0c;你可以编辑文章&#xff0c;管理数据。 注册登录

使用dockerfile来配置lnmp并运行wordpress以及镜像缩小体积

docker dockerfile创建镜像1.创建工作目录2.将各项安装包放入到对应的目录中3.在centos目录中用dockerfile创建centos&#xff1a;jiang镜像用来准备依赖包4.创建依赖包镜像5.创建docker1网段6.在centos&#xff1a;jiang依赖包镜像的前提下创建lnmp各个镜像进入各个目录编辑Do…

python+monkey+ 监控 crash,性能统计

目录 前言&#xff1a; monkey 压力测试 android monkey.ini 配置文件 代码分析 前言&#xff1a; 在软件开发中&#xff0c;测试和监控是非常重要的一个环节&#xff0c;它可以帮助我们更加全面地检测软件中的安全漏洞和风险。Python 是一种常用的脚本语言&#xff0c;可以…