摘抄自维基百科:在数学与计算机科学中,是指在函数的定义中使用函数自身的方法。
从字面上的意义来讲,就是在一个函数里面调用函数本身自己。javascript
function factorial(n){
if(n == 1 || n === 0){
return 1
}
return n * factorial(n-1)
}
复制代码
function fb(n){
if(n == 2 || n == 1){
return n
}
return fb(n-1) + fb(n-2)
}
复制代码
由两个例子咱们能够看出,在函数内,他还会再调用函数本身自己,而调用的那一层,可能就有值能够return出来,也可能再次调用函数自己。但不管是连续调用几回,他都有一个边界,像阶乘的边界是n=1,斐波那契数列的边界时n=2。
由此咱们能够总结出递归的特色:
1.有规律,有一个调用函数本身自己的过程。
2.有出口,有边界条件使得递归结束。
java
优势:
可以将屡次重复计算的过程用一小段代码表示出来,让代码看起来更为简洁
缺点:
1.递归是一个一次或屡次调用函数自己的过程,而在函数调用时,都要在栈内存中分配空间来存储变量、参数、地址等,这些都回消耗时间和空间,从而致使执行效率低下。
2.递归存在不少重复计算的过程,有可能会出现重叠计算,这样重复的计算也会致使效率低下。git
递归就是不断调用函数的过程。而当执行一个函数时,就会建立一个执行上下文,并压入执行上下文栈,当函数执行完毕时,执行上下文会从执行上下文栈中弹出。不断调用函数的过程,javascript会不断重复上面的过程,这是很是损耗的。咱们须要一个方法来优化这个过程,这个方法就是尾调用。github
尾调用的意思就是函数内部最后一个动做是函数调用,返回值只有函数,没有其余运算过程。
eg:
尾调用:函数
function a(x){
return f(x)
}
复制代码
非尾调用:优化
function b(x){
return f(x) + 1
}
复制代码
第一个函数执行时,虽然调用了一个函数,但原来的函数a已经执行完毕,执行上下文会弹出,再压入另一个函数f的执行上下文。这个过程当中至关于只压入一个执行上下文。也就是说函数a的执行上下文弹出后,才会压入函数f的执行上下文。
而第二个函数执行时,在调用函数的过程当中,函数b须要等函数f执行完与1相加后,才有返回值,这个过程至关于压入了两个执行上下文。
尾调用的做用就是减小建立执行上下文的个数。spa
咱们将阶乘函数优化一下:code
function factorial(n,sum){
if(n == 1 || n === 0){
return first
}
return factorial(n-1,n * sum)
}
复制代码
其中sum一开始的值为阶乘的最后一个数1。递归
若是您以为个人文章有用,欢迎点赞和关注,也欢迎光临个人我的博客 github.com/BokFangip