国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Python理解遞歸的方法總結

Python理解遞歸的方法總結

2021-05-23 12:23Python教程網 Python

在本篇文章里小編給大家分享了關于如何使用Python來理解遞歸的知識點內容,有興趣的朋友們學習下。

遞歸

一個函數在執行過程中一次或多次調用其本身便是遞歸,就像是俄羅斯套娃一樣,一個娃娃里包含另一個娃娃。

遞歸其實是程序設計語言學習過程中很快就會接觸到的東西,但有關遞歸的理解可能還會有一些遺漏,下面對此方面進行更加深入的理解

遞歸的分類

這里根據遞歸調用的數量分為線性遞歸、二路遞歸與多重遞歸

線性遞歸

如果一個遞歸調用最多開始一個其他遞歸調用,我們稱之為線性遞歸。

例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def binary_search(data, target, low, high):
  """
  二分查找,對有序列表進行查找,如果找到則返回True,否則返回False
  """
 
  if low > high:
    return False
  else:
    mid = (low + high) // 2
    if target == data[mid]:
      return True
    elif target < data[mid]:
      return binary_search(data, target, low, mid - 1)
    else:
      return binary_search(data, target, mid + 1, high)

雖然在代碼中有兩個binary_search,但他們是不同條件執行的,每次只能執行一次,所以是線性遞歸。

二路遞歸

如果一個遞歸調用可以開始兩個其他遞歸調用,我們稱之為二路遞歸

例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
def binary_sum(S, start, stop):
  """
  二路遞歸計算一個序列的和,例如S[0:5],就像切片的范圍一樣
 
  """
 
  if start >= stop:
    return 0
  elif start == stop - 1:
    return S[start]
  else:
    mid = (start + stop) // 2
    return binary_sum(S, start, mid) + binary_sum(S, mid, stop)

這個遞歸每次執行都會調用兩次該函數,所以說是二路遞歸,每次遞歸后,范圍縮小一半,所以該遞歸的深度是1+logn

多重遞歸

如果一個遞歸調用可以開始三個或者更多其他遞歸調用,我們稱之為多重遞歸

例如:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import os
 
def disk_usage(path):
  """
  計算一個文件系統的磁盤使用情況,
 
  """
 
  total = os.path.getsize(path)
  if os.path.isdir(path):
    for filename in os.listdir(path):
      childpath = os.path.join(path, filename)
      total += disk_usage(childpath)
  print('{0:<7}'.format(total), path)
  return total

os.path.getsize為獲得標識的文件或者目錄使用的即時磁盤空間大小。我理解的是如果該標識的是一個文件,那么就是獲得該文件的大小,如果是一個文件夾的話,那就是獲得該文件夾的大小,但不包括文件夾里邊的內容,就像是一個盒子中放了很多物品,但這里只計算了盒子的重量,但沒有計算物品的重量,也就是計算了一個空盒子。所以這個遞歸函數中的遞歸調用次數取決于這一層文件或文件夾的數量,所以是多重遞歸。

遞歸的不足

遞歸的不足顯然就是時間與空間的消耗 ,這篇文章中使用了緩存的方法減少了斐波那契數列的計算消耗,在這里我們使用另一種方式來改善那種壞的遞歸:

?
1
2
3
4
5
6
7
8
9
10
11
def fibonacci(n):
  """
  斐波那契數列計算,返回的是一個元組
 
  """
 
  if n <= 1:
    return (n, 0)
  else:
    (a, b) = fibonacci(n - 1)
    return(a + b, a)

 

將原來的二路遞歸改為了線性遞歸,減少了重復的計算。

python的最大遞歸深度

每一次遞歸都會有資源的消耗,每一次連續的調用都會需要額外的內存,當產生無限遞歸時,那就意味著資源的迅速耗盡,這明顯是不合理的。python為了避免這種現象,在設計時有意的限制了遞歸的深度,我們可以測試一下

?
1
2
3
4
5
def limitless(n):
  print('第' + str(n) + '次調用')
  n += 1
  return limitless(n)
limitless(1)

第988次調用
第989次調用
第990次調用
第991次調用
第992次調用
第993次調用
第994次調用
第995次調用
第996次調用
Traceback (most recent call last):
File “D:/github/Data-Structure/code/遞歸.py”, line 73, in
limitless(1)
File “D:/github/Data-Structure/code/遞歸.py”, line 70, in limitless
return limitless(n)
File “D:/github/Data-Structure/code/遞歸.py”, line 70, in limitless
return limitless(n)
File “D:/github/Data-Structure/code/遞歸.py”, line 70, in limitless
return limitless(n)
[Previous line repeated 992 more times]
File “D:/github/Data-Structure/code/遞歸.py”, line 68, in limitless
print(‘第' + str(n) + ‘次調用')
RecursionError: maximum recursion depth exceeded while calling a Python object

最終遞歸到996次停止了遞歸,也就是python的遞歸深度限制在了1000附近。

1000層的限制已經是足夠的了,但是還是有可能限制到某些計算,所以python提供了一個修改限制的方

?
1
2
3
4
5
6
7
8
9
import sys
def limitless(n):
  print('第' + str(n) + '次調用')
  n += 1
  return limitless(n)
 
print(sys.getrecursionlimit())#1000
sys.setrecursionlimit(2000)
limitless(1)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1994次調用
1995次調用
1996次調用
Traceback (most recent call last):
File “D:/github/Data-Structure/code/遞歸.py”, line 70, in limitless
return limitless(n)
File “D:/github/Data-Structure/code/遞歸.py”, line 70, in limitless
return limitless(n)
File “D:/github/Data-Structure/code/遞歸.py”, line 70, in limitless
return limitless(n)
[Previous line repeated 995 more times]
File “D:/github/Data-Structure/code/遞歸.py”, line 68, in limitless
print(‘第' + str(n) + ‘次調用')
RecursionError: maximum recursion depth exceeded while calling a Python objec

可見把這個深度該為2000后便多了1000次調用,但這個深度顯然不是設置多少就是多少,畢竟還有計算機CPU與內存的限制,比如吧深度改為10000,那么運行后

第3920次調用
第3921次調用
第3922次調用
第3923次調用

Process finished with exit code -1073741571 (0xC00000FD)

到達3923次便終止了,查詢-1073741571發現是遞歸棧溢出的問題。

尾遞歸

如果一個函數中所有遞歸形式的調用都出現在函數的末尾,我們稱這個遞歸函數是尾遞歸的。當遞歸調用是整個函數體中最后執行的語句且它的返回值不屬于表達式的一部分時,這個遞歸調用就是尾遞歸。尾遞歸函數的特點是在回歸過程中不用做任何操作,這個特性很重要,因為大多數現代的編譯器會利用這種特點自動生成優化的代碼。

Python解釋器在對于一次函數調用中,會使用一個棧幀來保存當前調用的函數的信息,如輸入參數、返回值空間、計算表達式時用到的臨時存儲空間、函數調用時保存的狀態信息以及輸出參數。因此在遞歸的調用中,這種未執行完的函數會一層一層的占用大量的棧幀。如果將遞歸的調用放到函數執行的最后一步,那么執行完這步,該次函數的棧幀就會釋放,調用函數的新棧幀就會替換掉之前的棧幀,所以無論調用的深度有多少次,都只會占用一個棧幀,那也就不會發生棧溢出的問題。這就是尾遞歸。

所以根據需要,尾遞歸必須是線性遞歸,并且遞歸調用的返回值必須立即返回。

拿一個階乘遞歸函數舉例

?
1
2
3
4
5
6
7
8
9
def factorial(n):
  """
  階乘遞歸函數
 
  """
  if n == 0:
    return 1
  else:
    return n * factorial(n - 1)

上邊這個是一個普通的遞歸,下面把他改成尾遞歸的形式

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def facttail(n, res):
  """
  階乘尾遞歸,res初始為1
 
  """
 
  if n < 0:
    return 0
  elif n == 0:
    return 1
  elif n == 1:
    return res
  else:
    return facttail(n - 1, n *res)

這個函數比之前那個還多了個res,第一種每次調用完要乘n,這里的res就起了相同的作用,由于尾遞歸每一層的棧幀要釋放,所以通過res來作為相乘的過程。我個人認為尾遞歸的難度就在于參數的設計,因為它的前提條件就是調用后什么也不再執行了,所以要作為傳遞的東西就得提前通過參數設計傳遞,總之要想設計一個尾遞歸的算法還是需要好好思考一下的。

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 美日韩一区 | 亚洲欧美激情精品一区二区 | 无码一区二区三区视频 | 免费观看一级毛片 | 久久久久亚洲精品 | 成人精品福利视频 | 一区二区视频在线观看 | 亚洲一区二区av | 黄色av免费观看 | 欧美99| 日本在线视频免费观看 | 欧美一区永久视频免费观看 | 色综合天天天天做夜夜夜夜做 | 九九九在线 | 国产精品免费久久久久久 | 亚洲精品国产电影 | 亚洲视频1区 | 精品视频免费观看 | www一区| 欧美一区二区在线视频 | 午夜精品视频在线观看 | 久久久久久毛片免费看 | 欧美日韩视频一区二区 | 欧美性猛片 | 亚洲一区二区三区视频 | 成人动慢| 成人免费视频观看 | 日韩一二区| 在线精品一区 | 久久久91精品国产一区二区三区 | 国产精品区二区三区日本 | 牛牛电影国产一区二区 | 国产高清精品一区二区三区 | 探花在线观看 | 国产精品一区二区在线观看 | 一级做a爰片久久毛片免费陪 | 欧美日韩国产一区二区三区 | 国产色视频在线播放 | 一区二区三区国产 | 欧美一级看片a免费观看 | 中文字幕1区2区3区 日韩免费高清视频 |