将树形递归转换为loop

class Stack(object):
    def __init__(self,**kwargs):
        self.__dict__.update(kwargs)
    def __str__(self):
        return '|'.join(
            ['%s:%s'%(k,getattr(self,k))
             for k in sorted(self.__dict__)])
    __repr__ = __str__

def fab(n):
    if n==1 or n==2:
        return 1
    return fab(n-1) + fab(n-2)

def xfab(n):       
    rst = 0
    stack = [Stack(n=n,stage=0)]
    while stack:
        #print(stack,rst)
        crt=stack.pop()
        if crt.stage == 0: 
            if crt.n == 1 or crt.n == 2:
                rst = 1
                continue
            else:
                crt.stage = 1
                stack.append(crt)
                stack.append(Stack(n=crt.n-1,stage=0)) 
                continue               
        if crt.stage == 1: 
            crt.adv = rst
            crt.stage = 2
            stack.append(crt)
            stack.append(Stack(n=crt.n-2,stage=0))            
            continue
        if crt.stage == 2:
            rst = crt.adv + rst
            continue        
    return rst

虽然loop繁杂多了,但是它有以下好处:

1.不会像递归函数那样栈溢出

2.对递归过程有了更多控制,例如你可以选择广度优先

再如:

#----------递归--------------------------------
def tmove(n,a=0,b=1,c=2):
    if n==1:
        yield a,c
    else:
        yield from tmove(n-1,a,c,b)
        yield a,c
        yield from tmove(n-1,b,a,c)

def fmove(n,a=0,b=1,c=2,d=3):
    if n==1:
        yield a,d
    else:
        i = int((math.sqrt(1+8*n)-1)/2)
        yield from fmove(n-i,a,d,b,c)
        yield from tmove(i,a,b,d)
        yield from fmove(n-i,c,b,a,d)          

#----------循环--------------------------------
def xtmove(n,a=0,b=1,c=2):
    stack = [Stack(n=n,a=a,b=b,c=c,stage=0)]
    while stack:
        crt=stack.pop()    
        if crt.n == 1:
            yield crt.a,crt.c
            continue
        if crt.stage==0:
            crt.stage=1
            stack.append(crt)
            stack.append(Stack(n=crt.n-1,a=crt.a,b=crt.c,c=crt.b,stage=0))
            continue
        if crt.stage==1:
            yield crt.a,crt.c
            stack.append(Stack(n=crt.n-1,a=crt.b,b=crt.a,c=crt.c,stage=0))

def xfmove(n,a=0,b=1,c=2,d=3):
    stack = [Stack(n=n,a=a,b=b,c=c,d=d,stage=0)]
    while stack:
        crt=stack.pop()
        if crt.n == 1:
            yield crt.a,crt.d
            continue
        i = int((math.sqrt(1+8*crt.n)-1)/2)
        if crt.stage==0:
            crt.stage=1
            stack.append(crt)
            stack.append(Stack(n=crt.n-i,a=crt.a,b=crt.d,c=crt.b,d=crt.c,stage=0))
            continue
        if crt.stage==1:
            yield from xtmove(n=i,a=crt.a,b=crt.b,c=crt.d)
            stack.append(Stack(n=crt.n-i,a=crt.c,b=crt.b,c=crt.a,d=crt.d,stage=0))

if __name__=='__main__':
    for x,y in xfmove(10000000000):
        pass
    for x,y in fmove(10000000000):
        pass

虽然不太清楚实践中会不会出现这种巨大的参数以至于让递归栈溢出,但至少心里有个底了,以后处理复杂问题,先构建递归函数,再写个loop版.

小参数用递归,大参数就用loop.

原文地址:https://www.cnblogs.com/xiangnan/p/3569772.html