摘抄自維基百科:在數學與計算機科學中,是指在函數的定義中使用函數自身的方法。
從字面上的意義來講,就是在一個函數裏面調用函數本身自己。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