信春哥!Python遞迴原地滿狀態變顯式堆棧!入教即送尾遞迴最佳化!

來源:互聯網
上載者:User
問題:

有Python函數一枚,用遞迴寫成。運行時超出Python的遞迴深度,現欲將其由在堆棧中分配空間改為在堆中分配空間(即用malloc)。

解決方案:

首先,from heaprecursion import *。然後對目標函數進行改造,假設要改造的遞迴函式為def func(p1, p2):

1.把函數中的遞迴調用func(exp1,exp2)改成yield RECURSION(exp1,exp2),即把所有"func"替換成"yield RECURSION"。

2.把函數中所有的"return"替換成yield。如果是尾遞迴return func(exp1, exp2)則改成yield TAIL(exp1, exp2)。

最後這樣調用改造好的函數:heaprun(f, exp1, exp2)

例子:
from heaprecursion import *

def sumlist(l):
    if len(l)==0: return 0
    x=l.pop()
    y=sumlist(l)
    return x+y

改造成這樣:    
def sumlist2(l):
    if len(l)==0: yield 0
    x=l.pop()
    y=yield RECURSION (l)
    yield x+y; 
調用:
heaprun(sumlist2, range(10000))
    
def factorial(n, accu):
    if n==0:
        return 1
    else:
        return factorial(n-1, accu*n)
改造成這樣:
def factorial2(n, accu):
    if n==0:
        yield accu
    else:
        yield TAIL(n-1, accu*n)
調用:
heaprun(factorial2, 10000, 1)

t=(1,
   (2,
    4,
    (5,
     6,
     7)),
   (3,
    8,
    9))

def inorder(t):
    if type(t) is int:
        print t
    else:
        inorder(t[1])
        print t[0]
        inorder(t[2])
改造成這樣:
def inorder2(t):
    if type(t) is int:
        print t
    else:
        yield RECURSION(t[1])
        print t[0]
        yield TAIL(t[2])
調用:
heaprun(inorder2, t)

heaprecursion.py代碼如下:
def forward(it, arg):
    # move iterator 'it' by calling 'next'(when 'arg' is None) or 'send'
    # return what 'next' or 'send' returns, or None if 'it' is at its end
    try:
        if arg==None:
            return it.next()
        else:
            return it.send(arg)
    except StopIteration: pass
    return None

        
class RECURSION(object):
    def __init__(self, *args):
        self.args=args
    
class TAIL(RECURSION):
    pass

def heaprun(f, *args):
    stack=[f(*args)]
    param=None
    while(1):
        v=forward(stack[-1], param)
        if isinstance(v, RECURSION):
            if type(v)==TAIL:
                stack.pop()
            stack.append(f(*(v.args)))
            param=None
        else:
            stack.pop()
            if stack:
                param=v
            else:
                return v
 限制:

目前heaprecursion.py只對自遞迴起作用,還不能用於互遞迴。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.