[轉載] Python 遞歸 深入理解遞歸 Python遞歸剖析,絕對讓你看懂!

參考鏈接: Python | print()中的結束參數

目錄

?遞歸剖析 遞歸的兩個過程 return 返回值 詳解

? ? 遞歸思路二分法和遞歸尾遞歸遞歸練習題

??

?

?

?

遞歸剖析?

遞歸真的很重要,之前學的時候,學的一知半解,以為真正了解,每次想到遞歸,就記得一句:返回給函數的調用者,嗯?函數調用者,你是說外部,還是內部啊?疑問太多了,還有就是被告知一句:遞歸能解決的問題,循環都能解決,所以就更加不重視遞歸了!直到接觸算法后,在解決問題時,最快,最容易理解的解法就是遞歸,但是此時的遞歸卻是看不太懂為什么要這樣做!我先來說下,在算法中遇到可以用遞歸輕松完成的:希爾排序、歸并排序、快速排序、反轉鏈表及各種反轉問題、二叉樹的深度遍歷、二叉樹的各種題基本可以用、全排列…還有算法步驟里需要用到,太多了,所以,遞歸非常重要!“To iterate is human, to recurse divine 迭代是人,遞歸是神”,接下來,我也是看了很多算法書和視頻,重點來整理下遞歸!?

?遞歸的兩個過程?

首先“遞歸”包括兩個過程:遞“去”的過程,“歸”回的過程!先從一個簡單的遞歸函數講起?

def di_gui(n):

? ? print(n, "<===1====>")

? ? if n > 0:

? ? ? ? di_gui(n - 1)

? ? print(n, '<===2====>')

?

?

di_gui(5) # 外部調用后打印的結果是?

?

?遞歸的執行過程:首先,遞歸會執行“去”的過程,只需要滿足終止條件,就會一直在函數內,帶著更新的參數,調用函數自身,注意:到內部調用函數, 以下面的代碼不會被執行,而是暫停阻塞;此時 隨著函數每調用一次自身,還沒有觸發 返回值和到達終止條件,等同于在原來的基礎上不斷“向下/向內”開辟新的內存空間,記住,每次調用一次函數,就不是處在同一空間(想象下《盜夢空間》里的情景,夢中夢,都是處于不同的空間)? ?什么時候“遞”去的過程結束?記住有兩種情況>>> 一是:當前這層空間函數全部執行結束(終止條件),二是:執行到了return 返回值,直接返回;? 重點來理解下,首先是一,看上面的列子,例子中沒有return,但是不斷的調用后,最終還是停止了,因為最后n=0時,di_gi(0)還是去調用,從上往下執行時,遇到if n>0 它被終止了,走不下去了,表明,自己能到達的這層空間已經全部執行完畢;接下來請原地返回吧,返回到哪里?返回到函數的調用者,好我們返回到 di_gui(0),把“到內部調用函數” 以下的代碼全部執行完;執行完,看代碼走到末尾,以為走出了最外層函數?注意了,此時它所處的空間并不是最外層哦,因為之前它被調用就在空間里面,所以回到的是 di_gui(1)的這一層空間,現在才是真正的開始“回”,所以繼續把di_gui(1)的這一層空間,“到內部調用函數”以下的代碼全部執行完,回到di_gui(2)的這一層空間…直到到達最開始 從外部調用,讓參數5進入的最外層空間位置,才走出來!表示《盜夢空間》里,柯布醒了!? 回來看下,代碼輸出的結果:5 4 3 2 1 00 1 2 3 4 5 ( 注意00這兩個是在同一層空間哦)? ?從內存角度(本質)來分析:每調用一次函數,都會單獨開辟一份棧幀空間,遞歸函數就是不停的開辟和釋放棧幀空間的過程,具體來理解下:一個普通函數從執行到結束,就是一個開辟空間和釋放空間的過程;而遞歸函數是在調用最外層函數時,先開辟一個最外層空間,每調用一次自身,就會在最外層空間內,再自己開辟本次的空間(所以遞歸耗內存)(還有一種說法是,不斷的本次空間的基礎上再開辟空間,等于是不斷的嵌套,其實這兩種說法本質上是一樣的,因為信息都可以做到不共享),空間之間如果不通過參數傳遞或者用return 返回值,信息是不共享的,如下圖↓↓↓??

??

?遞歸的數據共享情況:遞歸每一層間的數據是獨立的,不共享,但是可以通過參數或者返回值來形成共享,參數具體在傳入的是“引用類型”(比如列表)? 遞歸 必須要有一個出口,如果沒有出口就會重復調用,不斷的開辟棧幀空間??

# 獲取最大遞歸層數:

import sys

res=sys.getrecursionlimit()

print(res) # 結果:1000

# sys.setrecursionlimit(800) 可以自己設置最大遞歸層數

?

解釋含有 return 返回值的遞歸,記住 return的返回流程是:先計算,再返回 ,來看下一段求階乘的代碼:?

def jie_cheng(n):

? ? if n <= 1:

? ? ? ? return 1

? ? return n * jie_cheng(n - 1)

? ??

print(jie_cheng(5))

?

?

return 是返回到函數調用者,遞歸函數和普通函數也是一樣的,所以遞歸最后一層空間走到盡頭(一是:指向完畢,二是:遇到return,回顧一下而已)遇到return,就要開始返回了,返回到它的調用者(即是阻塞的位置),直到回到最外層空間如果上面的內容看懂了的話,試著解析下:下面這段代碼的執行流程?

def get_num(num):

? ? if num > 2:

? ? ? ? get_num(num - 1)

? ? print(num)

?

?

get_num(4) # 輸出結果為:2 3 4

?

?

?

?代碼變化一下:?

?

def get_num(num):

? ? if num > 2:

? ? ? ? get_num(num - 1)

? ? else:

? ? ? ? print(num)

?

?

get_num(4) # 輸出結果為 2

?

'''

解析一下:加了else后,首先代碼區有兩個分支,

在num>2時,執行會有遞歸,當n=4 是開辟一層空間;

n=3時開辟一層空間,此時 get_num(2) 再開辟一個空間,

當它從上往下執行過程中,在他本層空間遇到if num>2 不成立,所以走分支 else,直接打印出來;

此時代碼還沒結束,回到上一層空間,num=3, num>2 已經進入了if 不會走else,

num=4 也不會走else,所以這兩層空間沒有值輸出!

'''

?

?return 返回值 詳解?

上面這一大部分,就算是遞歸入門了,接下來才剛剛開始哦!還要繼續講 return ;先來看下這幾段代碼:求全排列的一部分遞歸代碼,試著分別寫出運行結果,并依次分析原因↓↓↓?

# 例1:

def fullpermutation(list):

? ? if list is None:

? ? ? ? return None

? ? if len(list) == 1:

? ? ? ? return [list]

? ? res = []

? ? pivot = list[0]

? ? remain = fullpermutation(list[1:])

? ? print(remain)

?

?

print(fullpermutation([1, 2, 3]))??

'''

輸出結果為:

[[3]]

None

None

'''

?

遞歸只會在兩種情況下觸發“回”的過程,上述是在最后一層空間是碰到了return,所以給回到它的調用處(阻塞處),因為return會給調用者返回一個值,所以在本層空間,remain接收到了一個值:[[3]];接著執行下面的代碼,即是打印remain,所以輸出“[[3]]”,執行完print,等于回到了上一層空間,又到了調用處(阻塞處),那么這層空間還有返回值嗎?答案是沒有,所以“最后一層空間是碰到了return 給它返回的值 只會給最后一層使用”,所以接下來兩層都是打印空!?

# 例2:

def fullpermutation(list):

? ? if list is None:

? ? ? ? return None

? ? if len(list) == 1:

? ? ? ? return [list]

? ? res = []

? ? pivot = list[0]

? ? return fullpermutation(list[1:])

?

?

print(fullpermutation([1, 2, 3]))

'''

輸出結果為:

[[3]]

'''

?

這次是,在最后一層返回時,獲得了一個返回值 [[3]] ,然后回到上一層時,前面又有return 表示需要把本層的返回值,返回到上層的接收處,重復,直到回到最外層,這個從底層傳上來的返回值,一直傳到了最外層,所以才打印出來的,只有最后一層,但是每次一層都獲得了返回值,和例子1 后面兩層沒有返回值是不同的哦!?

# 例3:

def fullpermutation(list):

? ? if list is None:

? ? ? ? return None

? ? if len(list) == 1:

? ? ? ? return [list]

? ? res = []

? ? pivot = list[0]

? ? remain = fullpermutation(list[1:])

? ? print(list)

?

?

print(fullpermutation([1, 2, 3]))

'''

輸出結果為:

[2, 3]

[1, 2, 3]

None

'''

?

最后一層碰到return,觸發會的過程,回到調用處,執行阻塞處下面的代碼,打印list,這個list是什么?它就是本層空間 參數的規模(因為代碼寫的是規模不斷變小從[1,2,3]>>>[2,3]>>>[3]),顯然,從最后一層回到上一層,此時規模是[2,3],所以打印list 就是[2, 3];接著繼續回到上一層,即是最外層,規模是[1,2,3],所以打印[1, 2, 3],最后的None是因為最外層函數,沒有返回值,所以才打印出None?

# 例4:

def fullpermutation(list):

? ? if list is None:

? ? ? ? return None

? ? if len(list) == 1:

? ? ? ? return [list]

? ? res = []

? ? pivot = list[0]

? ? remain = fullpermutation(list[1:])

? ? return list

?

?

print(fullpermutation([1, 2, 3]))

'''

輸出結果為:

[1, 2, 3]

'''

?

依照上面的步驟,觸發回的過程,只要沒有到達最外層,return list 返回本層的規模(參數規模),那么這個返回值就會給本層的接收者 remain 不可能給最外層的接收者,雖然這里沒有打印 remain的值,但是這里的remain和第一個列子中的remain,后面層數是有返回值的哦(下面例子就會體現),本例,返回到最外層時,list的本層規模為 [1,2,3] 最外層接收者接收到,然后打印出來,所以是[1,2,3]?

# 例5:

def fullpermutation(list):

? ? if list is None:

? ? ? ? return None

? ? if len(list) == 1:

? ? ? ? return [list]

? ? res = []

? ? pivot = list[0]

? ? remain = fullpermutation(list[1:])

? ? print(remain)

? ? return list

?

?

print(fullpermutation([1, 2, 3]))

'''

輸出結果為:

[[3]]

[2, 3]

[1, 2, 3]

'''

?

看上面的例子,這次我們是打印了 remain,因為返回的過程中,指向阻塞處(調用處)下面的代碼,每次return list 即是 在本層返回 當前的參數規模,所以 remain 是能接收本層的返回值的,所以會打印 [[3]] ,[2, 3] ;最后 [1, 2, 3] 是最外層打印的?

# 例6:

def fullpermutation(list):

? ? if list is None:

? ? ? ? return None

? ? if len(list) == 1:

? ? ? ? return [list]

? ? res = []

? ? pivot = list[0]

? ? remain = fullpermutation(list[1:])

? ? print(remain)

? ? print(list)

? ? return list

?

?

print(fullpermutation([1, 2, 3]))

'''

輸出結果為:

[[3]]

[2, 3]

[2, 3]

[1, 2, 3]

[1, 2, 3]

'''

?

?這個,就是所有的融合;通過上面的代碼我們來總結下return的返回值:最后一層遇到的return 需要執行 回的過程,此時的返回值 值會返回給最后的調用處的接收者;然后執行 阻塞處下面的代碼時,如果又遇到return 這里的返回值,如果沒有到達最外層,都是給本層的接收者!為什么要大費周章的講這個,是因為我們在寫遞歸時,往往不清楚return 要怎么寫,已及它的返回值是什么?接下來就要看下return 如何解決問題的? 請用遞歸完成一個字符串的反轉,輸入字符串“abcd”,完成翻轉成“dcba” 除了遞歸,我們可以直接用字符串的切片來完成,如下,但是這里是要講遞歸的思想,不體現方法優劣!??

s="abcd"

print(s[::-1])

?

想一下遞歸的思路該怎么做? 思路一:按照上面的例子,不斷的劃分子規模,我們選的是劃分原字符串的規模,都是往后截取的,比如第一次參數s=“abcd” 我們取參數s[1:] ,不斷調用函數,每次傳入參數為:‘bcd’ ‘cd’ ‘d’ ,這樣最后一層返回d 我們能拿到最后一個值,然后最后一個返回值d 加上 當前規模的第一個值,就完成了反轉,具體代碼如下:?

def str_reverse(s):

? ? if len(s) <= 1: # 遞歸出口

? ? ? ? return s

? ? # last = str_reverse(s[1:])

? ? # return last + s[0]

? ? return str_reverse(s[1:]) + s[0] # 每次返回最后一層的值,加上當前規模的第一個值

?

思路二:改變下子規模,我們這次不劃分原字符串,而是從它的索引下手,傳入最后一個元素的索引,不斷去遞歸索引的值,這時,變的是end的值,從 3 到 2 1 0,到0時觸發回的過程,返回當前索引的值,即是 a (不斷向前取值),這時我們再加上當前層的s,因為沒有劃分s所以s每一層都是等于‘abcd’的,我們每次取當前end索引指向的字符串的值,等于從前往后遍歷字符串 ‘abcd’ ,兩部分鏈接起來,就完成了反轉:每次的返回值為 a, ba , cba, dcba,?

def reve(str, end):

? ? if end == 0:

? ? ? ? return "" + str[0]

? ? last = str[end] + reve(str, end - 1)

? ? return last

?

?

s = "abcd"

print(reve(s, len(s) - 1))

?

?兩種做法都用到return,而是還有重要的遞歸思路,下面就來看看遞歸要用什么思路來解? 來試下“反轉鏈表”如何用遞歸做,首先對于一個單鏈表,要對它反轉,我們的思路依舊可以通過不斷向后劃分子規模,找到它的最后一個結點,然后從后往前依次改變每個結點的指向,讓最初的頭結點變成尾結點,讓它最后指向None;那么具體步驟是:用遞歸找到最后一個結點,我們可以通過前一個結點的next區域,不斷遞歸,找到下一個結點,直到當前結點的next是None,說明它就是最后一個結點,這也是我們遞歸的出口,那么依次讓它返回,同時改變指向,就完成了,具體看下面的圖解:??

class ListNode:?

? ? def __init__(self, x):

? ? ? ? self.val = x

? ? ? ? self.next = None

?

?

class Solution:

? ? def ReverseList(self, pHead):

? ? ? ? if pHead is None: # 判斷傳入的頭結點是否為空

? ? ? ? ? ? return None

? ? ? ? if pHead.next is None: # 如果只有一個結點,直接返回結點;同時也是遞歸的出口

? ? ? ? ? ? return pHead

? ? ? ? last_node = self.ReverseList(pHead.next) # last_node永遠只接收到了最后一個結點

? ? ? ? pHead.next.next = pHead # 后一個結點,指向前一個結點

? ? ? ? pHead.next = None # 前一個結點,在不同的層,先指向None,如果到達最外層也會指向None

? ? ? ? return last_node # 最后返回最后一個結點,表示反轉成功

?

到達最后一層,觸發回的過程,返回 last_node 結點給最后第四層,執行阻塞處下面的代碼,因為pHead.next.next 是None,它不用改變也行,直接到 return last_node 把 last_node給第三層用… 第三層獲得 last_node ,執行阻塞處下面的代碼,改變指向,pHead.next.next 是“5結點”,它的指針指向 pHead,即是上一個結點,然后上一個結點指向None;因為這里并不需要用一個temp 來保存前一個指針信息,表面上是斷開鏈接,會丟掉數據,其實不會丟掉,因為他們不再同一層;可以用temp先保存前一個結點的數,這屬于遞歸的寫,在我的文章>>>反轉鏈表多種解法 有提到,這里不細說!? 直到 回到最外層,起初的頭結點,自然會指向None,最后返回 last_node即可 這才是 鏈表反轉 遞歸的詳細過程,果然和我開始理解的不一樣,當初怎么都無法理解,直到用斷點調試,才發現真正的過程,是這樣,大家可以用斷點調試下,看下代碼的具體過程,下面是測試代碼:?

class ListNode:

? ? def __init__(self, x):

? ? ? ? self.val = x

? ? ? ? self.next = None

?

?

class Solution:

? ? def ReverseList(self, pHead):

? ? ? ? if pHead is None:

? ? ? ? ? ? return None

? ? ? ? if pHead.next is None:

? ? ? ? ? ? return pHead

? ? ? ? last_node = self.ReverseList(pHead.next)

? ? ? ? print(last_node.val)

? ? ? ? pHead.next.next = pHead

? ? ? ? pHead.next = None

? ? ? ? return last_node

?

? ? def print_list(self, node):? # 打印測試

? ? ? ? if node is None:

? ? ? ? ? ? return None

? ? ? ? while node:

? ? ? ? ? ? print(node.val, end="")

? ? ? ? ? ? node = node.next

? ? ? ? print()

?

?

if __name__ == '__main__':

? ? n1 = ListNode(1)? # 依次實例5個結點

? ? n2 = ListNode(2)

? ? n3 = ListNode(3)

? ? n4 = ListNode(4)

? ? n5 = ListNode(5)

? ? n1.next = n2? # 依次將結點鏈接起來,形成一個鏈表

? ? n2.next = n3

? ? n3.next = n4

? ? n4.next = n5

? ? n5.next = None

?

? ? obj = Solution()

? ? print(obj.ReverseList(n1).val)

? ? # obj.print_list(n1) # 1 2 3 4 5

? ? # obj.print_list(obj.ReverseList(n1))? # 5 4 3 2 1

?

遞歸思路?

?思想: 1.找到當前這個值與上一個值的關系 2.找到程序的出口 有個明確的結束條件 3.假設當前功能已經完成 每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少? 遞歸思路: (1)找重復:看哪一部分是 實現函數的變化;每次進入更深一層遞歸時,問題規模相比上次遞歸都應有所減少 (2)找變化:變化的量應該作為參數 (3)找邊界(出口):終止條件? 遞歸可以分為: (1)直接量+小規模子問題 (2)多個小規模子問題 (3) “切蛋糕”思維 (4)找遞推公式,等價交換公式??

二分法和遞歸?

# 二分法一定是在排序好的數據里使用

?

lst = [33, 22, 44, 55, 66, 88, 77, 99, 101, 238, 345, 456, 567, 678, 789]

n = 76

lst.sort()

left = 0

right = len(lst) - 1

?

while left <= right:? # 條件是 開頭<=結尾

? ? middle = (left + right) // 2

? ? if lst[middle] > n:? # 每次用對折后,中間的數和 查找對象比較

? ? ? ? right = middle - 1

? ? elif lst[middle] < n:

? ? ? ? left = middle + 1

? ? elif lst[middle] == n:

? ? ? ? print("找到了")

? ? ? ? break

else:

? ? print("這個數不在列表中")

?

# 遞歸函數來做

lst = [22, 33, 44, 55, 66, 77, 88, 99, 101, 238, 345, 456, 567, 678, 789]

?

?

def func(n, left, right):

? ? if left <= right:? # 邊界

? ? ? ? mid = (left + right) // 2

? ? ? ? if n > lst[mid]:

? ? ? ? ? ? left = mid + 1

? ? ? ? ? ? func(n, left, right)? # 遞歸的入口,目的是再確定一次中間的位置

? ? ? ? elif n < lst[mid]:

? ? ? ? ? ? right = mid - 1

? ? ? ? ? ? func(n, left, right)

? ? ? ? elif n == lst[mid]:

? ? ? ? ? ? print("找到了")

? ? ? ? ? ? return? # 遞歸出口

? ? else:

? ? ? ? print("沒有這個數")

? ? ? ? return? # 遞歸的出口

?

?

func(66, 0, len(lst) - 1)

?

# 升級:如果找到了要求的數,請返回它的索引

?

lst = [22, 33, 44, 55, 66, 77, 88, 99, 101, 238, 345, 456, 567, 678, 789]

?

?

def func(n, left, right):

? ? if left <= right:? # 邊界

? ? ? ? mid = (left + right) // 2

? ? ? ? if n > lst[mid]:

? ? ? ? ? ? left = mid + 1

? ? ? ? ? ? return func(n, left, right)? # 每一層都要返回給上一層的調用者

? ? ? ? elif n < lst[mid]:

? ? ? ? ? ? right = mid - 1

? ? ? ? ? ? return func(n, left, right)

? ? ? ? elif n == lst[mid]:

? ? ? ? ? ? print("找到了")

? ? ? ? ? ? return mid? # 多層函數只會將返回值返回給上一層的調用者

? ? else:

? ? ? ? print("沒有這個數")

? ? ? ? return -1

?

?

print(func(66, 0, len(lst) - 1))

?

尾遞歸?

尾遞歸(自己調用自己,且非表達式:把值放到參數中算)

?

?

>>>求斐波那契數列第n位是幾?(尾遞歸做法)

?

def feibo(num, res, temp):

? ? ?#使用尾遞歸法求解斐波那契數量的第num個數字

? ? ?if num == 0:

? ? ? ? ? return res

? ? ?else:

? ? ? ? ? return feibo(num - 1, temp, res + temp)

?

print(feibo(10,0,1))

?

# 直接遞歸? 尾遞歸 與 循環 的對比

?

import time

?

?

def Fib_recursion(num):

? ? '''

? ? 直接使用遞歸法求解斐波那契數量的第num個數字

? ? '''

? ? if num < 2:

? ? ? ? return num

? ? return Fib_recursion(num - 1) + Fib_recursion(num - 2)

?

?

def Fib_tail_recursion(num, res, temp):

? ? '''

? ? 使用尾遞歸法求解斐波那契數量的第num個數字

? ? '''

? ? if num == 0:

? ? ? ? return res

? ? else:

? ? ? ? return Fib_tail_recursion(num - 1, temp, res + temp)

?

?

def Fib_circle(num):

? ? '''

? ? 直接使用循環來求解

? ? '''

? ? a = 0

? ? b = 1

? ? for i in range(1, num):

? ? ? ? c = a + b

? ? ? ? a = b

? ? ? ? b = c

? ? return c

?

?

if __name__ == '__main__':

? ? num_list = [5, 10, 20, 30, 40, 50]

? ? for num in num_list:

? ? ? ? start_time = time.time()

? ? ? ? print(Fib_recursion(num))

? ? ? ? end_time = time.time()

? ? ? ? print(Fib_tail_recursion(num, 0, 1))

? ? ? ? end_time2 = time.time()

? ? ? ? print(Fib_circle(num))

? ? ? ? end_time3 = time.time()

? ? ? ? print('正在求解的斐波那契數字下標為%s' % num)

? ? ? ? print('直接遞歸耗時為 :', end_time - start_time)

? ? ? ? print('尾遞歸調用耗時為:', end_time2 - end_time)

? ? ? ? print('直接使用循環耗時為:', end_time3 - end_time2)

?

遞歸練習題?

>>>打印f-e的數:

?

def pri(f, e):

? ? if f > e:

? ? ? ? return

? ? else:

? ? ? ? print(f)

? ? ? ? return pri(f + 1, e)

?

?

pri(1, 6)

?

?

>>>求一個列表的和:

def sum_lis(li, f):? # 如果單獨是傳入一個列表,它體現不了變化

? ? """

? ? :param li: 傳入一個列表

? ? :param f: 列表起始位置

? ? :return: 列表和

? ? """

? ? if f == len(li) - 1:? # 表示起始位置也是結束位置,即只有一個元素

? ? ? ? return li[f]

?

? ? return li[f] + sum_lis(li, f + 1)

?

?

print(sum_lis([1, 2, 3, 4, 5], 0))

?

# 多引入一個 變化的參數,可以想到第一個元素加上剩下的元素,規模不斷變小

?

# 需求:求 1+2+3+4........100 的和

num = 1

count = 0

while num <= 100:

? ? count += num

? ? num += 1

print(count)

?

'''

思路:

sum(1) + 2 +3.....100

sum(2) + 3........100

sum(3) + 4........100

...

sum(98)+99+100

sum(99) + 100

sum(100)

?

sum(100) = sum(99) + 100

sum(99) = sum(98) + 99

sum(98) = sum(97) + 98

.....

?

sum(2) = sum(1) + 2

?

sum(1) = 1

'''

# 用遞歸函數解決

def sum(num):

? ? if num == 1:? # 出口

? ? ? ? return 1

? ? return num + sum(num - 1)? # 一直返回sum(num-1)+num,每次遞歸調用,有return才能有返回值

?

?

print(sum(100))

?

>>>需求:打印斐波那契數列

def fibo(num):? # 參數是表示第n個斐波那契數,函數整體表示獲取斐波那契數列中第n個數字的值

? ? if num == 1 or num == 2:? # 第一個和第二個都是1

? ? ? ? return 1? # 返回1,出口

? ? return fibo(num - 1) + fibo(num - 2)? # 規律,后一項加上后兩項,就等于斐波那契數列第n個數字的值

?

?

if __name__ == '__main__':

? ? list_num = []? # 創建一個空列表,開始

? ? for i in range(1, 21):? # 遍歷1-20

? ? ? ? list_num.append(fibo(i))? # 注意這里開始調用函數,獲得一個斐波那契數字,將獲取到的值填充到list_num

? ? print(list_num)

?

?

# 最佳解法:

def fei_bo(n):

? ? if n <= 1:

? ? ? ? return (n, 0)

? ? else:

? ? ? ? (a, b) = fei_bo(n - 1)

? ? ? ? return (a + b, a)

?

?

print(fei_bo(5))

# 這里是線性的解法,不再重復計算前一項已知的數

?

# 求最大公約數

def maxg(m, n):

? ? if n == 0:

? ? ? ? return m

? ? return maxg(n, m % n)

?

?

print(maxg(6, 0))

?

# 最大公約數:

# 如果m%n=0 則n是m的最大公約數;例如4%2=0 則2是最大公約數?

# 如果m%n=K 則 n%k=?0 >>> f(m,n)=f(n,m%n)

?

?

>>>用遞歸實現列表排序:

def ins(li, k):

? ? if k == 0:

? ? ? ? return

? ? # 對前K個元素進行排序

? ? ins(li, k - 1)

? ? # 把位置K的元素插入到前面的部分

? ? x = li[k]

? ? index = k - 1

? ? while x < li[index]:

? ? ? ? li[index + 1] = li[index]

? ? ? ? index -= 1

? ? li[index + 1] = x

? ? print(li)

?

?

ins([1, 4, 3, 2], 3)

?

>>>需求:遞歸實現遍歷目錄

?

import os

?

?

def get_alldirfile(source_path):? # 定義一個函數獲取用戶輸入的路徑名下所有目錄和文件

? ? if not os.path.exists(source_path):? # 判斷用戶輸入的目錄是否存在

? ? ? ? return? # 不存在,直接返回,結束該函數,找到一個出口

? ? list_name = os.listdir(source_path)? # lisdir獲取所有目錄,并全部放到一個列表中

? ? for flie_dirname in list_name:? # 遍歷下所有的文件目錄名

? ? ? ? abs_path = os.path.join(source_path, flie_dirname)? # 拼接成絕對路徑

? ? ? ? # 判斷下一級是否是目錄還是文件,是文件結束,是目錄繼續深入,直到是文件結束

? ? ? ? if os.path.isfile(abs_path):? # 是文件

? ? ? ? ? ? print("file_path:%s" % (abs_path))

? ? ? ? # 也可進行復制操作,open(abs_path,"w",encoding="utf-8")

? ? ? ? if os.path.isdir(abs_path):

? ? ? ? ? ? get_alldirfile(abs_path)? # 遞歸函數

?

?

if __name__ == '__main__':

? ? path = r"F:\日語\快樂50音"

? ? get_alldirfile(path)

?

# 優化

import os

?

?

def file_get(file_path, n):

? ? list_file = os.listdir(file_path)

? ? for file in list_file:

? ? ? ? abs_file = os.path.join(file_path, file)

? ? ? ? if os.path.isdir(abs_file):

? ? ? ? ? ? print("\t" * n, file)

? ? ? ? ? ? file_get(abs_file, n + 1)

? ? ? ? else:

? ? ? ? ? ? print("\t" * n, file)

?

?

file_get("D:\KuGou", 1)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/540562.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/540562.shtml
英文地址,請注明出處:http://en.pswp.cn/news/540562.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

laravel 項目遷移_在Laravel遷移

laravel 項目遷移Before moving forward we need to know some facts about it, 在繼續前進之前&#xff0c;我們需要了解一些事實&#xff0c; Resources: In these directories, we have already a js, lang, sass and view page. Where, sass and js file holf their uncom…

Python之list對應元素求和

本次分享將講述如何在Python中對多個list的對應元素求和&#xff0c;前提是每個list的長度一樣。比如&#xff1a;a[1,2,3], b[2,3,4], c[3,4,5], 對a,b,c的對應元素求和&#xff0c;輸出應為[6,9,12].    方法一&#xff1a;   直接求解&#xff0c;按照對應元素相加的…

[轉載] Python中str跟int的轉換

參考鏈接&#xff1a; Python中的類型轉換 字符串str轉換成int: int_value int(str_value) int轉換成字符串str: str_value str(int_value) a100 b666 #int轉str類型 print(int轉str類型) print(int轉str&#xff1a; str(a)) #str轉int類型 print(str轉int類型…

ot協議是什么_OT的完整形式是什么?

ot協議是什么OT&#xff1a;主題外 (OT: Off Topic) OT is an abbreviation of "Off Topic". OT是“ Off Topic”的縮寫 。 It is an expression, which is commonly used in Gmail or messaging platform. It shows that the email that has been sent is irrelev…

[轉載] python中字符串編碼形式及其所占字節

參考鏈接&#xff1a; Python中的字節對象與字符串 1.常見字符串編碼錯誤 在使用Python讀文件時經常遇到編碼問題引起的錯誤&#xff0c;比如&#xff1a; UnicodeDecodeError: gbk codec cant decode byte 0x80 in position 30: illegal multibyte sequence 遇到這種異…

[AtCoder-ARC073F]Many Moves

題目大意&#xff1a;   有一排n個格子和2枚硬幣。   現在有q次任務&#xff0c;每一次要你把其中一枚硬幣移到x的位置上&#xff0c;移動1格的代價是1。   兩枚硬幣不能同時移動&#xff0c;任務必須按次序完成。   現在告訴你兩枚硬幣初始狀態所在的位置a和b&#xf…

ScalavsKotlin

Is Scala better that Kotlin? No..., Is Kotlin better than Scala? No... Scala比Kotlin更好嗎&#xff1f; 不...&#xff0c;Kotlin勝過Scala嗎&#xff1f; 沒有... Both programming languages have their own profits and are for a specific set of development. It…

工業智能相機與基于PC的機器視覺的區別比較

隨著科技的日漸成熟&#xff0c;機器視覺得到了飛速發展。由于嵌入式技術的發展,近幾年智能相機性能顯著提高&#xff0c;越來越多必須依賴于PC處理的應用開始向智能相機平臺傾斜。低成本、高可靠性及易于安裝維護等優勢&#xff0c;使得機器視覺在制造業上的規模性應用越來越普…

[轉載] python skimage在圖像處理中的用法

參考鏈接&#xff1a; 在Python中打印單變量和多變量 基于python腳本語言開發的數字圖片處理包&#xff0c;比如PIL,Pillow, opencv, scikit-image等。 PIL和Pillow只提供最基礎的數字圖像處理&#xff0c;功能有限&#xff1b;opencv實際上是一個c庫&#xff0c;只是提供了py…

scala元組 數組_Scala中的數組

scala元組 數組Scala中的數組 (Arrays in Scala) An array is a linear data structure with a fixed number of elements. It is a collection that stores a fixed number Arrays in Scalf elements of the same datatype. In Scala, an array is 0 indexed, i.e. the first …

OpenStack —— DevStack一鍵自動化安裝

一、DevStack介紹Devstack目前是支持Ubuntu16.04和CentOS 7&#xff0c;而且Devstack官方建議使用Ubuntu16.04&#xff0c;所以我們使用Ubuntu 16.04進行安裝。默認無論是Devstack和OpenStack&#xff0c;都是采用Master的代碼進行安裝&#xff0c;這樣經常會出現&#xff0c;今…

[轉載] Python學習筆記——運維和Shell

參考鏈接&#xff1a; 在C / C&#xff0c;Python&#xff0c;PHP和Java中交換兩個變量 目錄 什么是運維 運維第一工具-shell編程 shell歷史 執行腳本 基本語法 Shell腳本語法 條件測試&#xff1a;test [ if/then/elif/else/fi case/esac for/do/done …

scala java混合_Scala特性混合

scala java混合Scala | 特性混合 (Scala | Trait Mixins ) In Scala, the number of traits can be extended using a class or an abstract class. This is known as Trait Mixins. For extending, only traits, the blend of traits, class or abstract class are valid. If …

Scala鑄造

Scala中的類型 (Types in Scala) Type also know as data type tells the compiler about the type of data that is used by the programmer. For example, if we initialize a value or variable as an integer the compiler will free up 4 bytes of memory space and it wi…

/ 卡路里_最大卡路里

/ 卡路里Problem statement: 問題陳述&#xff1a; Shivang is very foodie but he has a diet plan. He has an array of elements indicating the calorie of food he can consume on that day. In his diet plan, he can’t eat on for three consecutive days. But since …

[轉載] Python類中的私有變量和公有變量

參考鏈接&#xff1a; Python中的私有變量 我們這里就直奔主題&#xff0c;不做基礎鋪墊&#xff0c;默認你有一些Python類的基礎&#xff0c;大家在看這篇博客的時候&#xff0c;如果基礎知識忘了&#xff0c;可以去菜鳥教程 從一個簡單的類開始 class A(): #定義一…

OpenCV探索之路(二十五):制作簡易的圖像標注小工具

搞圖像深度學習的童鞋一定碰過圖像數據標注的東西&#xff0c;當我們訓練網絡時需要訓練集數據&#xff0c;但在網上又沒有找到自己想要的數據集&#xff0c;這時候就考慮自己制作自己的數據集了&#xff0c;這時就需要對圖像進行標注。圖像標注是件很枯燥又很費人力物力的一件…

固件的完整形式是什么?

FW&#xff1a;前進 (FW: Forward) FW is an abbreviation of "Forward". FW是“ Forward”的縮寫 。 It is an expression, which is commonly used in Gmail or messaging platform. It is also written as FWD or Fwd or Fw. It shows that the email has been s…

[轉載] python __slots__ 詳解(上篇)

參考鏈接&#xff1a; Python的__name __(特殊變量) python中的new-style class要求繼承Python中的一個內建類型&#xff0c; 一般繼承object&#xff0c;也可以繼承list或者dict等其他的內建類型。 在python新式類中&#xff0c;可以定義一個變量__slots__&#xff0c;它的作…

委托BegionInvoke和窗體BegionInvoke

委托BegionInvoke是指通過委托方法執行多線程任務&#xff0c;例如&#xff1a; //定義委托成員變量 delegate void dg_DeleAirport(); //指定委托函數 dg_DeleAirport dga AirportBLL.DeleteHistoryTransAirport; //通過BeginInvoke以異步線程方式執行委托函數&#xff0c;可…