簡體   English   中英

在遞歸函數中用尾遞歸替換for循環

[英]Replacing a for loop with tail recursion in a recursive function

我正在嘗試使以下函數完全尾部遞歸,例如從那里獲取討厭的循環。 原因是我正在嘗試將解決方案輕松轉換為涉及使用顯式堆棧的迭代解決方案。 請指教。

def permutations(A):
    P = []
    P2 = []
    permutations_recursive(A, [], P)
    permutations_tail_recursive(A, [], P2, 0)
    print(P2)
    return P

def permutations_recursive(first, last, perms):
    if len(first) == 0:
        perms.append(last)
    else:
        for i in range(len(first)):
            permutations_recursive(
                first[:i] + first[i+1:],
                last + [first[i]],
                perms)

封閉式迭代模擬:

def permutations(A):
    P = []
    permutationsI(A, P)
    print(P)

def permutationsI(A, perms):
   stack = [(A, [])]
    while len(stack):
        first, last = stack.pop()
        if len(first):
            for i in range(len(first)):
                stack.append((first[:i] + first[i+1:],last + [first[i]]))
        else:
            perms.append(last)

permutations([1,2,3])
>>[[3, 2, 1], [3, 1, 2], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]]

完全遞歸函數應為:

def permutations_comp_recursive(first, last, perms, i):
    if len(first) == 0:
        perms.append(last)
    elif i == len(first):
        pass
    else:
        permutations_comp_recursive(first, last, perms, i+1)
        if first:
                permutations_comp_recursive(
                first[:i]+first[i+1:],
                last + [first[i]],
                perms, 0)

為了獲得良好的性能,我建議使用numpy解決方案

編輯1:現在,以下內容應使用列表推導進行尾部遞歸。 這在python中使用workarount進行尾遞歸(並且省略了最后2個參數-結果作為返回值傳遞):

import itertools as it
class Recurse(Exception):
    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs

def recurse(*args, **kwargs):
    raise Recurse(*args, **kwargs)

def tail_recursive(f):
    def decorated(*args, **kwargs):
        while True:
            try:
                return f(*args, **kwargs)
            except Recurse as r:
                args = r.args
                kwargs = r.kwargs
                continue
    return decorated

@tail_recursive
def permutations_tail_recursive(first, last, direct=False):
    if len(first) == 0 or not all(first):
        return last
    else:
        l = len(first[0]) if direct else len(first)
        if last:
            return recurse([fi[:i]+fi[i+1:] for fi, i in it.product(first, range(l))],
                [last[j] + first[j][i] for j, i in it.product(range(len(last)), range(l))], True)
        else:
            return recurse([first[:i]+first[i+1:] for i in range(l)],
                [first[i] for i in range(l)], True)

這不是經過優化的,而是使用循環。 我不確定是否可以將其與上面沒有循環的代碼進行組合-可能會再次調查。 itertools.permutations可以用於此應用程序。

暫無
暫無

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

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