簡體   English   中英

Python,將迭代函數轉換為遞歸函數

[英]Python, Make an iterative function into a recursive function

我創建了一個迭代函數,輸出4 3 2 1 0 1 2 3 4。

def bounce2(n):
    s = n
    for i in range(n):
        print(n)
        n = n-1

    if n <= 0:
        for i in range(s+1):
            print(-n)
            n = n-1
    return
bounce2(4)

如果我想要一個完全相同的遞歸函數,我該怎么想?

嘗試這個:

def bounce(n):
    if n >= 0:
        print(n)
        bounce(n - 1)

        if n:
            print(n)

bounce(4)

輸出將是:4 3 2 1 0 1 2 3 4

預期產量:

4 3 2 1 0 1 2 3 4

讓我把它放到一個圖表中:

4
  3
    2
      1
        0
      1
    2
  3
4

我們把它放到代碼中:

def bounce(n):
    print(n)
    if n:
        bounce(n - 1)
        print(n)

或者我可以將其視為樹遍歷 - 向下和向上(在這種情況下,樹是非常線性的):

↓
  4
↓ | ↑
  3
↓ | ↑
  2
↓ | ↑
  1
↓ | ↑
  0

有多種方法可以進行樹遍歷 ,我會在這里選擇DFS - 深度優先搜索

DFS偽代碼:

procedure DFS(G,v):
    label v as discovered
    for all edges from v to w in G.adjacentEdges(v) do
        if vertex w is not labeled as discovered then
            recursively call DFS(G,w)

實際上它是專為圖形設計的,而不僅僅是樹木; 對於樹木,我們不必做“被發現的標簽”部分。

將此DFS轉換為Python:

def dfs(node):
    for child_node in node:
        dfs(child_node)

4 3 2 1 0情況下,我們不需要for becase,只有n > 0只有一個或零個子節點 - n - 1

def our_dfs(n):
    if n > 0:
        child_node = n - 1
        our_dfs(child_node)

但這只是遍歷而沒有真正有用的東西。 讓我們注入“業務邏輯”:

def bounce(n):
    # stuff that happens before we go down
    print(n)
    # descend
    if n > 0:
        child_node = n - 1
        bounce(child_node)
    # stuff that happens after we are back from processing the subtree
    if n > 0:
        print(n)

因為我們相信良好的工藝,我們想要生成干凈的代碼(好吧我現在開始開玩笑)我們想要只做一件事的函數 - 一個函數用於DFS,一個函數代表我們的樹,單獨的函數用於我們的業務邏輯:

def dfs(node, child_factory, before_stuff, after_stuff):
    before_stuff(node)
    for child_node in get_child_nodes(node):
        dfs(child_node, child_factory, before_stuff, after_stuff)
    after_stuff(node)

def get_child_nodes(n):
    if n:
        yield n - 1

def print_before(node):
    print(node)

def print_after(node):
    if node:
        print(node)

def bounce(n):
    dfs(n, get_child_nodes, print_before, print_after)

bounce(4)

也許我們可以通過使用嵌套函數使dfs函數更簡單:

def dfs(node, child_factory, before_stuff, after_stuff):
    def f(node):
        before_stuff(node)
        for child_node in get_child_nodes(node):
            f(child_node)
        after_stuff(node)
    f(node)

嘿,看看它,我還有一個想法......我們可以將它修改為一個函數,它返回一個可以執行DFS的函數( 閉包 ):

def make_dfs(child_factory, before_stuff, after_stuff):
    def dfs(node):
        before_stuff(node)
        for child_node in get_child_nodes(node):
            dfs(child_node)
        after_stuff(node)
    return dfs

所以反彈計划現在變成:

def get_child_nodes(n):
    if n:
        yield n - 1

def print_before(node):
    print(node)

def print_after(node):
    if node:
        print(node)

def make_dfs(child_factory, before_stuff, after_stuff):
    def dfs(node):
        before_stuff(node)
        for child_node in get_child_nodes(node):
            dfs(child_node)
        after_stuff(node)
    return dfs

bounce = make_dfs(get_child_nodes, print_before, print_after)

bounce(4)

那么,這個解決方案有什么好處呢? (注意:仍在開玩笑,部分)你知道,Python有一個遞歸限制 有多少函數調用可以嵌套,這個數字非常低。 使用遞歸函數處理未知輸入是一個很大的缺點(有時甚至是安全問題)。 所以現在怎么辦? 好吧,只需用基於堆棧的東西替換make_dfs的實現(參見DFS Wikipedia頁面)而不是遞歸。 完成。 你不必觸摸任何其他東西。

@ mehrdad-pedramfar發表了一個很好的答案。 你也可以試試這個更精致的:

def my_recursion(current_value, first_portion):
    if current_value == 5:
        return
    print(current_value)
    if current_value == 0 or not first_portion:
        my_recursion(current_value + 1, False)

    elif first_portion:
        my_recursion(current_value - 1, True)


my_recursion(4, True)

基本上與第一個相同。 輸出是不同的 - 你會得到雙倍的0.只是為了表明你可以在遞歸調用之前和之后打印。

def bounce(n):

    if n >= 0:
        print(n)
        bounce(n - 1)
        print(n)

3 2 1 0 0 1 2 3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM