在Python中将递归函数转换为非递归函数

时间:2015-10-01 23:31:37

标签: python recursion iteration qgis

如何将此递归函数转换并优化为迭代函数。我正在尝试使用方向图编程一个累积流量的函数,但是,对于非常大的方向图,函数只会崩溃。我正在用Python编程,并且不能增加系统递归限制。

def AcumulacionCelda(x,y):
            if Acum[x,y]==NoData:
                Acum[x,y]=1
                for m, n in product(range(-1,2), range(-1,2)):
                    if m==-1 and n==-1 and Direcciones[x+m,y+n]==4:
                        AcumulacionCelda(x+m,y+n)
                        Acum[x,y]=Acum[x,y]+Acum[x+m,y+n]
                    elif m==-1 and n==0 and Direcciones[x+m,y+n]==5:
                        AcumulacionCelda(x+m,y+n)
                        Acum[x,y]=Acum[x,y]+Acum[x+m,y+n]
                    elif m==-1 and n==1 and Direcciones[x+m,y+n]==6:
                        AcumulacionCelda(x+m,y+n)
                        Acum[x,y]=Acum[x,y]+Acum[x+m,y+n]
                    elif m==0 and n==1 and Direcciones[x+m,y+n]==7:
                        AcumulacionCelda(x+m,y+n)
                        Acum[x,y]=Acum[x,y]+Acum[x+m,y+n]
                    elif m==1 and n==1 and Direcciones[x+m,y+n]==8:
                        AcumulacionCelda(x+m,y+n)
                        Acum[x,y]=Acum[x,y]+Acum[x+m,y+n]
                    elif m==1 and n==0 and Direcciones[x+m,y+n]==1:
                        AcumulacionCelda(x+m,y+n)
                        Acum[x,y]=Acum[x,y]+Acum[x+m,y+n]
                    elif m==1 and n==-1 and Direcciones[x+m,y+n]==2:
                        AcumulacionCelda(x+m,y+n)
                        Acum[x,y]=Acum[x,y]+Acum[x+m,y+n]
                    elif m==0 and n==-1 and Direcciones[x+m,y+n]==3:
                        AcumulacionCelda(x+m,y+n)
                        Acum[x,y]=Acum[x,y]+Acum[x+m,y+n]

            return;

for i, j in product(range(1,Filas-1), range(1,Columnas-1)):
      AcumulacionCelda(i,j)

2 个答案:

答案 0 :(得分:1)

首先让我们重构一系列if语句,使递归函数更简单:

def AcumulacionCelda(x,y):
    d = {(-1, -1):  4,
         (-1, 0) :  5,
         (-1, 1) :  6,
         (0, -1) :  3,
         (0, 0)  :  'dummy',
         (0, 1)  :  7,
         (1, -1) :  2,
         (1, 0)  :  1,
         (1, 1)  :  8}

    if Acum[x, y] == NoData:
        Acum[x, y] = 1
        for m, n in product(range(-1,2), range(-1,2)):
            if Direcciones[x+m, y+n] == d[m, n]:
                AcumulacionCelda(x+m, y+n)
                Acum[x,y] += Acum[x+m, y+n]

现在要使函数迭代而不是递归,我们需要创建一个队列来存储我们需要部分挂起并稍后重新访问的各种状态和任务。我们不是递归调用,而是向队列追加要完成的任务,然后是一个新的任务,用于递归'计算,然后break(或continue)到主循环的新迭代。

def AcumulacionCelda(x,y):
    if Acum[x, y] != NoData:
        return
    Acum[x, y] = 1
    d = {(-1, -1):  4,
         (-1, 0) :  5,
         (-1, 1) :  6,
         (0, -1) :  3,
         (0, 0)  : 'dummy',
         (0, 1)  :  7,
         (1, -1) :  2,
         (1, 0)  :  1,
         (1, 1)  :  8}
    keys = tuple(product(range(-1,2), range(-1,2)))[::-1]
    queue = [('Loop', (x, y), list(keys))]

    while queue:
        instruction, coords, directions = queue.pop()
        x, y = coords
        if instruction == 'Loop':
            while directions:
                m, n = directions.pop()
                if Direcciones[x+m, y+n] == d[m, n]:
                    queue.append(('Loop', (x, y), directions))
                    queue.append(('Add', (x, y), (m, n)))
                    if Acum[x+m, y+n] == NoData:
                        Acum[x+m, y+n] = 1
                        queue.append(('Loop', (x+m, y+n), list(keys)))
                    break
        elif instruction == 'Add':
            m, n = directions
            Acum[x, y] += Acum[x+m, y+n]

答案 1 :(得分:0)

这是针对此类问题的低级解决方案。我认为有一个更好的工具。您可能想要使用Dijkstra的最短路径算法。您可能需要查看NetworkX模块算法部分。将x,y位置映射为网络图中的点,使边上的权重成为x,y城市位置的平方差。