当前位置: 首页 > Web前端 > JavaScript

JavaScript中的递归

时间:2023-03-27 02:00:37 JavaScript

递归RecursionToiterateishuman,torecurse,divine.理解了迭代,上帝就理解了递归。本文将重点介绍JavaScript,并提供一些Rust示例。概述递归是程序函数调用自身。递归需要边界条件、递归前向段和递归返回段。当不满足边界条件时,递归前进;当满足边界条件时,递归返回。帕斯卡三角:从递归理解。在中国,帕斯卡三角被称为阳辉三角,因为阳辉三角在中国的记载比欧洲帕斯卡三角的记载早了数百年。一个可以产生递归的条件调用本身:用最小的函数解决问题,并产生一个与原问题形式相同的新问题。递归退出:递归考虑有限的问题。出口是递归调用的最后一次调用的出口。递归和循环的区别在于满足一定的条件,重复执行同一段代码。而递归就是不断调用自己行为的函数。常见的是for-in/for-of循??环,而递归常见于数学问题:斐波那契函数。缺点是比较耗内存。可以使用tail回调来回溯(Backtrack)一个递归调用过程,这就是回溯。回溯是一种使用递归实现的算法思想。用通俗一点的方式来解释递归和回溯:我们走在路上,前面有一个多岔路口,因为不知道该走哪条路,所以需要试一试。尝试的过程是一个函数。我们选择了一个方向,后来发现还有一个岔路口。这个时候,我们就需要做出另一种选择。所以我们需要根据上次尝试的结果再试一次,也就是在函数内部再次调用函数,这就是递归的过程。这样重复几次之后,我们发现这次选择的路不通。这时候我们知道在上一个路口选错了,只好回到之前的路口,选择另一条路。这就是回溯的思想。递归算法(recursivealgorithm)递归问题中,以JavaScript/Rust为例,有几个经典问题ArraysummationfibonaccifunctionJavaScript使用递归实现深拷贝React-Router递归实现routesVue中递归组件的配置经典fibonacci函数示例经典斐波那契JavaScript实现exportdefaultfunctionfibonacci(n){if(n<0)thrownewError("输入的数字不能小于0");如果(n===1||n===2){返回1;}返回斐波那契数(n-2)+斐波那契数(n-1);}constfi=斐波那契数列(7);控制台日志(fi);经典的FibonacciRust实现(带有测试)fnmain(){println!("Hello,world!");让f1=斐波那契(1);println!("{}",f1);让f2=斐波那契(2);println!("{}",f2);f3=斐波那契(3);println!("{}",f3);让f4=斐波那契(4);println!("{}",f4);}pubfnfibonacci(n:i32)->u32{ifn<0{panic!("输入的数字不能小于0")};如果n==1||n==2{return1}fibonacci(n-2)+fibonacci(n-1)}#[cfg(test)]modtests{使用crate::fibonacci;#[特st]fnfibonacci1(){让结果=fibonacci(1);assert_eq!(结果,1);}#[test]fnfibonacci2(){letresult=fibonacci(2);assert_eq!(结果,1);}#[test]fnfibonacci3(){letresult=fibonacci(3);assert_eq!(结果,2);}}从求和到递归//循环varsum=0;for(vari=1;i<=10;i++){sum+=i;}console.log(sum);//递归函数sum(n){if(n==1)return1;returnsum(n-1)+n;}varamount=sum(10);console.log(amount);fnmain(){println!("Hello,world!");while_sum_fn();}fnwhile_sum_fn(){让mutsum=0;让muti=0;而我<=10{总和+=我;我+=1;println!("总和:{}",总和);}println!("{sum}")}Rustfor循环和js中的循环非常相似这里最大的不同是rust使用while语句而不是JavaScript中的for语句默认值选项:输入目标类型+设置类型functiondeepClone(target){consttargetType=typeoftarget;if(targetType==="object"||targetType==="function"){让克隆=Array.isArray(target)?[]:{};for(constkeyintarget){clone[key]=deepClone(target[key]);}返回克隆;}returntarget;}Values:SpecificSpecific(weakMap)functiondeepClone(target,map=newMap()){consttargetType=typeoftarget;if(targetType==='object'||targetType==='function'){letclone=Array.isArray(target)?[]:{};如果(地图。得到(目标)){返回地图。得到(目标);}map.set(目标,克隆);if(Object.prototype.toString.call(target)==='[objectDate]'){clone=newDate(target)}if(Object.prototype.toString.call(target)==='[objectObject]'||Object.prototype.toString.call(target)==='[objectArray]'){for(constkeyintarget){clone[key]=deepClone(target[key],map)}}returnclone;}returntarget;}那么深拷贝需要考虑很多js数据类型(包括es5+中的新数据类型)deep拷贝的缺点也很明显。对于大对象,可能会非常占用计算机资源。基于这个特性,React社区为React和JavaScript创建了一个不可变数据库:immerimmutable.jsimmutabledata。每次修改后,都会得到一个新的数据(但会尽量复用原有数据),以弥补深拷贝数据时的性能问题。reactrouter递归实现配置route//递归函数constrotuerViews=(routerItems)=>{if(routerItems&&routerItems.length){returnrouterItems.map(({path,Component,children,redirect})=>{returnchildren&&children.length?(}>}>{rotuerViews(children)}//递归遍历子路径由{redirect?(}>):(}>)}):(}>}>);});}};vue中树组件的递归(如何在组件中使用自己)扩展:尾递归(TailRecursion)尾递归,首先我们要明白什么是尾调用?实际上,函数调用发生后,最后执行的语句就是函数调用尾递归,即函数调用发生在函数的末尾(Tail)(但调用本身就是尾递归)。尾递归在普通尾调用的基础上,多了两个特点:函数本身在尾调用(Self-called);可以对其进行优化,使计算只占用一个常量的栈空间(StackSpace)。一个例子functiontailFactorial(n,total){if(n===1)returntotal;返回tailFactorial(n-1,n*total);}functionfactorial(n){returntailFactorial(n,1);}factorial(5);//120递归非常耗内存,因为需要同时保存几千条或几百条通话记录,很容易造成“栈溢出”错误(stackoverflow)。但是对于尾递归,由于只有一条调用记录,所以不会出现“栈溢出”的错误。尾递归有什么问题?空间优化策略:尾递归递归调用的缺点是保存的调用栈(callframe)。如何优化尾递归?函数中发生尾递归时,返回的结果相差不大,存入栈没有意义。我们不需要这些事情发生是没有意义的。所以电脑可以保存一些内容。递归展开还是以阶乘为例:functionfact(n){if(n<=0){return1;}else{returnn*fact(n-1);}}6*fact(5)6*(5*fact(4))6*(5*(4*fact(3))))6*(5*(4*(3*(2*(1*1))))))//<=final扩展的特点是:函数并没有真正运行起来,需要很大的内存空间进行扩展。如果内容太大,很容易爆栈。尾递归函数仍然是递归函数。如果不优化,就会像普通的递归函数一样爆栈。扩多少层还是扩多少层。不会爆栈是因为语言编译器或解释器做了“尾递归优化”,所以不会爆栈。总结什么是递归?从杨辉的三角到递归,再到递归和循环的区别。递归和回溯递归算法的常见经典问题。尾递归及其优化和递归展开参考。递归算法简介及应用场景[0]递归使用场景[1]递归算法[2]Javascript中的递归使用方法[3]尾调用优化[4]面试官:说说如何优化递归——尾递归优化[5]tail递归为什么可以优化?[6]递归怎么写[7]引用1.https://www.cnblogs.com/hands...2.https://www.cnblogs.com/Shine...3.https://zhuanlan.zhihu.com/p/...4.https://developer.aliyun.com/...5.http://ruanyifeng.com/blog/20...6.https://cloud.tencent.com/dev...7.https://zhuanlan.zhihu.com/p/...8.https://leetcode.cn/circle/ar...