一、什么是函數遞歸?
函數的嵌套調用是:函數嵌套函數。函數的遞歸調用:它是一種特殊的嵌套調用,但是它在調用一個函數的過程中,又直接或間接地調用了它自身。
def foo():
print('from foo')
foo()
foo() # 進入死循環
如果遞歸函數不斷地調用函數自身,那么這個遞歸函數將會進入一個死循環,因此我們應該給遞歸函數一個明確的結束條件。
1.1 直接調用
直接調用指的是:直接在函數內部調用函數自身。
import sys
print(f"最大遞歸層數: {sys.getrecursionlimit()}")
最大遞歸層數: 3000
import sys
# 修改遞歸層數
sys.setrecursionlimit(10000)
def foo(n):
print('from foo',n)
foo(n+1)
foo(0)
1.2 間接調用
間接調用指的是:不在原函數體內調用函數自身,而是通過其他的方法間接調用函數自身。
def bar():
print('from bar')
foo()
def foo():
print('from foo')
bar()
bar()
遞歸必須要有兩個明確的階段:
- 遞推:一層一層遞歸調用下去,進入下一層遞歸的問題規模都將會減小
- 回溯:遞歸必須要有一個明確的結束條件,在滿足該條件開始一層一層回溯。
遞歸的精髓在於通過不斷地重復逼近一個最終的結果。

'''
...
age(5) = age(4) + 2
age(4) = age(3) + 2
age(3) = age(2) + 2
age(2) = age(1) + 2
age(1) = 26
age(n) = age(n-1) +2
age(1) = 26 # n=1
'''
def age(n):
if n == 1:
return 26
res = age(n-1) + 2
return res
print(f"age(5): {age(5)}")
age(5): 34
二、為什么要用遞歸
遞歸的本質就是干重復的活,但是僅僅是普通的重復,我們使用while循環就可以了。」
lis = [1, [2, [3, [4, [5, [6, ]]]]]]
def tell(lis):
for i in lis:
if type(i) is list:
tell(i)
else:
print(i)
# print(f"tell(lis): {tell(lis)}")
tell(lis)
1
2
3
4
5
6
三、如何用遞歸?
3.1 二分法的應用
有一個從小到大排列的整型數字列表,我們判斷某一個數字是不是在這個列表里面。
動圖二分法查找數字23:

動圖二分法查找數字1:

nums = [1, 3, 7, 11, 22, 34, 55, 78, 111, 115]
for item in nums:
if item == 10:
print('find it')
break
else:
print('not exists')
not exists
對於上述的列表我們可能可以通過一個for循環實現我們需要的功能,但是當我們的列表中的元素個數非常多時,我們還用這種方法,那是極其復雜的,因此我們可以考慮使用二分法的思想實現。
from random import randint
nums = [randint(1, 100) for i in range(100)]
nums = sorted(nums)
print(nums)
[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 10, 11, 11, 11, 11, 12, 13, 13, 15, 16, 16, 20, 21, 21, 23, 24, 26, 26, 27, 28, 28, 31, 33, 33, 34, 35, 38, 38, 39, 40, 42, 43, 45, 45, 46, 46, 47, 47, 51, 52, 52, 53, 53, 55, 55, 56, 56, 57, 57, 57, 58, 59, 61, 62, 64, 66, 66, 67, 68, 69, 69, 71, 72, 72, 74, 74, 75, 76, 78, 78, 79, 79, 79, 79, 80, 82, 85, 88, 89, 90, 90, 91, 91, 91, 94, 99, 99, 100]
def search(search_num, nums):
mid_index = len(nums)//2
print(nums)
if not nums:
print('not exists')
return
if search_num > nums[mid_index]:
# in the right
nums = nums[mid_index+1:]
search(search_num, nums)
elif search_num < nums[mid_index]:
# in the left
nums = nums[:mid_index]
search(search_num, nums)
else:
print('find it')
search(7, nums)
[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 10, 11, 11, 11, 11, 12, 13, 13, 15, 16, 16, 20, 21, 21, 23, 24, 26, 26, 27, 28, 28, 31, 33, 33, 34, 35, 38, 38, 39, 40, 42, 43, 45, 45, 46, 46, 47, 47, 51, 52, 52, 53, 53, 55, 55, 56, 56, 57, 57, 57, 58, 59, 61, 62, 64, 66, 66, 67, 68, 69, 69, 71, 72, 72, 74, 74, 75, 76, 78, 78, 79, 79, 79, 79, 80, 82, 85, 88, 89, 90, 90, 91, 91, 91, 94, 99, 99, 100]
[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 10, 11, 11, 11, 11, 12, 13, 13, 15, 16, 16, 20, 21, 21, 23, 24, 26, 26, 27, 28, 28, 31, 33, 33, 34, 35, 38, 38, 39, 40, 42, 43, 45, 45, 46, 46, 47, 47]
[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 10, 11, 11, 11, 11, 12, 13, 13, 15, 16, 16, 20, 21]
[1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7]
[6, 6, 7, 7, 7]
find it
四、習題
'''
2. 使用遞歸打印斐波那契數列,(前兩個數的和得到第三個數,如:0 1 1 2 3 5 8...)
'''
# x = 0 # 1
# y = 1 # 2
# count = 0
# while count < 10:
# print(x) # 0,
# x, y = y, x + y
# count += 1
# import sys
# sys.setrecursionlimit(10)
# def feibo(x, y, end=999):
# if x > end:
# return
#
# print(x)
# x, y = y, x + y
# feibo(x, y)
#
#
# feibo(0, 1)
'''
x = 0 # 1
y = 1 --> # 2
x + y --> x # 3
x + 2y --> x + y --> y
'''
'''
一個嵌套很多層的列表,如l=[1,2,[3,[4,5,6,[7,8,[9,10,[11,12,13,[14,15]]]]]]],用遞歸取出所有的值
'''
l = [1, 2, [3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14, 15]]]]]]]
for i in l:
if type(i) == list:
for j in i:
print(j)
else:
print(i)
def get(lis):
for i in lis:
if type(i) == list:
get(i)
else:
print(i)
get(l)
