什麽是遞歸?先了解什麽是遞歸.
你好!歡迎閱讀我的博文,你可以跳轉到我的個人博客網站,會有更好的排版效果和功能。
此外,本篇博文為本人Pushy原創,如需轉載請註明出處:http://blog.pushy.site/posts/1519134018
一說起遞歸,我想每個人都不陌生.舉個從小就聽過的例子:從前有座山,山裏有座廟,廟裏有個和尚,和尚在講故事,從前有座山,山裏有座廟,廟裏有個和尚,和尚在講故事,從前有座山...,還有你從兩面相對的鏡子中看到的畫面,其實都是抽象出來的遞歸現象,但是嚴格來說並不是遞歸,因為會一直重復下去,沒有終止條件,那就稱為死循環了.有關遞歸和死循環的異同我們之後會說到,那麽現在先來了解一下什麽是遞歸?
那麽什麽是遞歸呢? 要理解遞歸,就得先了解什麽是遞歸
假設我們現在都不知道什麽是遞歸,我們自然想到打開瀏覽器,輸入到谷歌的網頁,我們點擊搜索遞歸,然後我們在為維基百科中了解到了遞歸的基本定義,在了解到了遞歸實際上是和棧有關的時候,你又蒙圈了,什麽是棧呢?數據結構沒學清楚,此時的你只能又打開谷歌,搜索什麽是棧.接下來你依次了解了內存/操作系統.在你基本了解好知識之後,你通過操作系統了解了內存,通過內存了解了棧,通過棧了解了什麽是遞歸這下你恍然大悟!原來這就是遞歸啊!
這下應該有點明白了吧,這個過程其實就是遞歸的過程,如果不了解遞歸,那就先了解什麽是遞歸,可能你會說這是個循環並不是遞歸,我們前面說到,遞歸是需要終止條件的,那麽你明白遞歸是什麽
2. 示例:
也許之前你在網絡上看到過這張圖片:
實際上這張圖就很形象地表達出了遞歸,這句嚇得我抱起了抱著抱著抱著我的小鯉魚的我的我的我如果從字面意義上看可能看不出是什麽意思,那麽我們可以通過代碼來實現同樣的效果:
function Recursion(depth) {
console.log(‘抱著‘);
if (!depth) {
console.log (‘我的小鯉魚‘)
} else {
Recursion(--depth); // 遞歸調用
}
console.log(‘的我‘);
}
console.log(‘嚇得我抱起了‘);
Recursion(2)
在終端的打印結果為如下,可以看到和上面的那段話是一樣的:
代碼其實十分簡單,但是需要理解的是:if
代碼塊的條件(!depth
)為遞歸調用的終止條件,在else
代碼塊內遞歸調用函數.我們前面有說到遞歸的過程是存在前行和退回階段的,那麽在前行階段我們在每次調用函數後,打印出了"抱著",並且當depth≠0
時重新調用該函數;在退回階段,將會去執行代碼console.log(‘的我‘);
再打印出"的我".
褚躍躍的圖也能比較清楚地反映出這個過程:
好了!這下你應該明白什麽是遞歸了吧?如果你還沒有明白什麽是遞歸的話,你可以看這裏
3. 應用:
3.1 斐波拉契數列:
有關遞歸應用的應用有很多,例如註明的斐波拉契數列就可以通過遞歸來實現:
def fib(x):
if x < 2:
return 0 if x == 0 else 1
# 當x > 2時,開始遞歸調用fib()函數:
return fib(x - 1) + fib(x - 2)
print(fib(6)) # 打印結果為:8
這裏需要對i<2
時的特殊情況做出判斷,當x==0
時,直接返回0
,當x==1
時,直接返回1
3.2 遍歷文件:
首先我們需要了解遍歷的算法:定義的file_display
函數以某個目錄(/home/pushy
)作為遍歷的起點.遇到一個子目錄時,就先接著遍歷子目錄(遞歸調用函數);遇到一個文件時,就直接對改文件進行操作(這裏只打印出文件的文件名):
import os
def file_display(filepath):
for each in os.listdir(filepath):
# 得到文件的絕對路徑:
absolute_path = os.path.join(filepath, each)
# 得到是否為文件還是目錄的布爾值:
is_file = os.path.isfile(absolute_path)
if is_file:
# 當前的絕對路徑為文件:
print(each)
else:
# 當前的絕對路徑為目錄:
file_display(absolute_path)
file_display(‘/home/pushy‘)
這樣我們就可以遍歷到/home/pushy
路徑下的所有文件:
另外我們還可以使用遞歸來創建目錄:
import os
def createFile(dirname):
exits = os.path.exists(dirname)
if exits:
return True
else:
# 開始遞歸調用函數,並接受其返回值:
rec_result = createFile(os.path.dirname(dirname))
if rec_result:
# 如果不存在該目錄,則創建dirname的目錄,並返回已經創建(存在)的值True:
os.mkdir(dirname)
return True
createFile(‘./aa/bb/cc‘)
4. 循環與遞歸:
好了,遞歸的知識差不多介紹完了.如果看完上邊大概已經了解了循環和遞歸的區別了.對了!簡單來說,循環是有去無回,而遞歸則是有去有回(因為存在終止條件).
舉個栗子,你用你手中的鑰匙打開一扇門,結果去發現前方還有一扇門,緊接著你又用鑰匙打開了這扇門,然後你又看到一扇們...但是當你開到某扇門時,發現前方是一堵墻無路可走了,你選擇原路返回.這就是遞歸
但是如果你打開一扇門後,同樣發現前方也有一扇們,緊接著你又打開下一扇門...但是卻一直沒有碰到盡頭,這就是循環.
參考資料:
[知乎]什麽是遞歸
七天學會NodeJs--遞歸算法
什麽是遞歸?先了解什麽是遞歸.