python--遞歸(附利用棧和隊列模擬遞歸)

  博客地址:http://www.cnblogs.com/yudanqu/python

 

1、遞歸

  • 遞歸調用:一個函數,調用的自身,稱爲遞歸調用
  • 遞歸函數:一個能夠調用自身的函數稱爲遞歸函數

  凡是循環能幹的事,遞歸都能幹app

方法:
一、寫出臨界條件
二、找這一次和上一次的關係
三、假設當前函數已經能用,調用自身計算上一次的結果再求出本次的結果

  下面咱們經過兩段代碼簡單看一下遞歸和非遞歸的區別:函數

    輸入一個大於等於1的數,求1到n的和!學習

1 # 普通函數方法
2 
3 def hanshu(n):
4     sum = 0
5     # 循環遍歷每個數字,將他們加到一個事先定義好的變量上,直到加完
6     for x in range(1, n+1):
7         sum += x
8     return sum

  下面看一下經過遞歸的方法:ui

1 # 遞歸
2 
3 def digui(n):
4     if n == 1:
5         return 1 # 若是n等於1證實已經遞歸到最後,返回1,這就是上述的臨界條件
6     else:
7         return n + digui(n-1) # 當沒有達到臨界條件時,用n加上對n-1的遞歸,每次都把n加進去,可是後面依然是使用當下這個遞歸函數,會再次調用計算n-1,直到遞歸結束,也就是將從n到1的數所有遞歸完

  在實際應用中,遞歸是十分消耗內存的,可是有些事情他很容易去作,很容易理解。下面,就經過一個案例介紹一下遞歸的用法。spa

 

2、遞歸遍歷目錄

  下面的內容我就經過解釋代碼來說解了,若是哪裏講的不清楚,歡迎你們下方評論提意見。操作系統

 1 import os # 因爲咱們遍歷目錄,因此要找到那個目錄並操做,os模塊包含廣泛的操做系統功能
 2 
 3 path = "" # 這是咱們要遍歷的目錄的路徑,須要本身寫進去
 4 
 5 # 既然是遞歸函數,那麼確定要有個函數,並且這個函數還將在函數內部再次被調用
 6 def getAllDir(path, sp = ''): # 參數中傳入路徑和sp,這個我最後說一句你就明白了
 7     # 獲得當前目錄下的全部文件
 8     filesList = os.listdir(path) # os.listdir()是os模塊下的一個方法,至關於Linux中的ls,查看全部文件
 9 
10     sp += "  " # 這個也先放一下
11     # 處理每個文件
12     for fileName in filesList: # 遍歷剛纔找到的目錄下的全部文件
13         # 判斷是不是目錄(要用絕對路徑)
14         fileAbsPath = os.path.join(path,fileName) # join是os模塊下將兩個路徑拼接在一塊兒的意思,第二個參數不能有斜槓。由於咱們要判斷一下這個文件是一個普通文件仍是一個目錄,全部要先把他的絕對路徑整理出來
15         if os.path.isdir(fileAbsPath): # isdir是判斷是否爲目錄,是則返回True
16             print(sp + "目錄:", fileName) # 打印當前這個文件,他是個目錄
17             getAllDir(fileAbsPath,sp = "  ") # 這裏就開始遞歸了,由於咱們要找到整個目錄裏的東西,因此當這個文件仍是個目錄的時候咱們須要繼續向下找
18         else:
19             print(sp + "普通文件:", fileName) # 若是僅僅是個普通文件,那麼他裏面也就沒有其餘文件了,就能夠直接打印他了
20 
21 
22 getAllDir(path) # 這裏是調用函數,讓遍歷開始
23 
24 # 最後我來講一下開始寫的那個sp,是space的意思,有人也許如今就明白了。那個其實就是讓咱們方便觀察,由於每次打印都是頂行寫的,咱們分不清他的目錄結構,因此經過空格來調整。在函數內部寫一個空格增長的表達式,可使調用次數和空格數相關起來,遞歸的越深,證實目錄的級越低,那麼空格越多

 

3、棧模擬遞歸遍歷目錄(深度遍歷)

 1 # 總體思路是沒有變得,這裏沒有寫到的也許是重複的,看下上面註釋就行了
 2 # 寫了一半想起來應該回來寫一下棧:棧就是一個容器,但它只有一個口,入棧出棧都從這一個口,並且這個棧很細,進去了就不能顛倒位置了,因此,每入棧一個元素他在最外面時候能夠出來,不然得等前面的走完了它才能夠出來
 3 import os
 4 
 5 def getAllDirDFS(path):
 6     stack = [] # 這裏是用棧來模擬,咱們先建立一個列表當作棧
 7     stack.append(path) # 首先,先向棧裏壓入路徑
 8 
 9     # 處理棧,當棧爲空時結束循環(棧爲空就說明棧裏沒有普通文件和目錄了,由於咱們是每操做一個要把那個取出來)
10     while len(stack) != 0:
11         # 從棧中取出數據
12         dirPath = stack.pop() # pop函數是刪除最後一個元素,同時還有一個返回值,就是去除的那個元素,咱們再接收一下等等用
13         # 目錄下全部文件
14         filesList = os.listdir(dirPath) # 這個和上面同樣
15 
16         # 處理每個文件,若是是普通文件則打印出來,若是是目錄則將該目錄地址壓棧
17         for fileName in filesList:
18             # print(dirPath)
19             fileAbsPath = os.path.join(dirPath,fileName)
20             # print(fileAbsPath)
21             if os.path.isdir(fileAbsPath):
22                 # 是目錄就壓棧
23                 print("目錄:" + fileName)
24                 stack.append(fileAbsPath) # 當是目錄時入棧,它這時就在最外面,下一次循環時候要取出棧的元素是否是仍是這個啊,既然是它的話就還有找他內部的東西,等把他找完了才繼續找和他並列的那些文件。就是說抓住一根繩子使勁往下找,找到頭沒有了才返回來,這就是深度優先遍歷
25             else:
26                 # 打印普通文件
27                 print("普通:" + fileName)
28 
29 getAllDirDFS(path)

 

 4、隊列模擬遞歸遍歷目錄(廣度遍歷)

 1 # 這回記住了,先說一下隊列,隊是一個兩端開口的模型,一頭進一頭出,固然還有雙向隊列,循環等等,咱們就簡單用一下最基本的隊列
 2 
 3 import collections # 隊列在python的包裏有,因此咱們直接調用一下,不用覺得這個很難,他也只不過是類型是queue,實際的思想是同樣的,入隊append,由於這個是在右側,也就是後方入隊,另外一邊出的話就是popleft,左側出,是否是很通俗,只是改了一下出來的口
 4 def getAllDirBFS(path):
 5     queue = collections.deque() # 建立一個隊列,只要記得後面用法就是上面我說的那個不一樣就能夠了
 6     queue.append(path)
 7 
 8     while len(queue) != 0:
 9         dirPath = queue.popleft() # 僅僅這裏不一樣,由於隊列模擬是另外一端出隊
10         filesList = os.listdir(dirPath)
11         for fileName in filesList:
12             fileAbsPath = os.path.join(dirPath,fileName)
13             if os.path.isdir(fileAbsPath):
14                 print('目錄:' + fileName)
15                 queue.append(fileAbsPath)
16             else:
17                 print('文件:' + fileName)
18 
19 getAllDirBFS(path)        
20 
21 # 你們想一下,棧是哪裏進哪裏出,也就是,剛進去的元素,接下來的一次循環又出來了,那即是一條路走到頭,是深度遍歷;那麼如今一頭進另外一頭出是什麼意思呢,就是即使判斷了這個是一個目錄,但我如今不執行你,我要把你前面這些都查一遍,找完是目錄的都添加在後面,以後再遍歷大家這些,就是把一層的內容找完再找下一層,被稱爲廣度優先遍歷。    

 

  寫這篇隨筆的時候沒有考慮到也許有些同窗還須要學習一下棧和隊列,我會在以後再進行一下總結。本人也是初學者,但願和你們一塊兒交流。code

 

 

  做者:漁單渠(yudanqu)blog

  博客地址:http://www.cnblogs.com/yudanqu/遞歸

相關文章
相關標籤/搜索