我想将数组上的递归算法转换为迭代函数。它不是尾部递归算法,具有两个递归调用,然后进行一些操作。 该算法是一种分而治之算法,其中在每个步骤中,将数组分为两个子数组,并将某些函数f应用于前两个结果。在实践中,f很复杂,因此迭代算法应使用函数f,在一个最小的工作示例中,我使用了一个简单的加法运算。
下面是python中递归程序的最小工作示例。
import numpy as np
def f(left,right):
#In practice some complicated function of left and right
value=left+right
return value
def recursive(w,i,j):
if i==j:
#termination condition when the subarray has size 1
return w[i]
else:
k=(j-i)//2+i
#split the array into two subarrays between indices i,k and k+1,j
left=recursive(w,i,k)
right=recursive(w,k+1,j)
return f(left,right)
a=np.random.rand(10)
print(recursive(a,0,a.shape[0]-1))
现在,如果我想迭代地编写此代码,我意识到我需要一个堆栈来存储中间结果,并且在每一步中,我都需要将f应用于堆栈顶部的两个元素。我只是不确定如何构建将元素放入堆栈而无需递归的顺序。这是一种尝试解决方案的尝试,该解决方案肯定不是最佳方法,因为似乎应该有一种方法可以删除第一个循环并仅使用一个堆栈:
def iterative(w):
stack=[]
stack2=[]
stack3=[]
i=0
j=w.shape[0]-1
stack.append((i,j))
while (i,j)!=(w.shape[0]-1,w.shape[0]-1):
(i,j)=stack.pop()
stack2.append((i,j))
if i==j:
pass
else:
k=int(np.floor((j-i)/2)+i)
stack.append((k+1,j))
stack.append((i,k))
while len(stack2)>0:
(i,j)=stack2.pop()
if i==j:
stack3.append(w[i])
else:
right=stack3.pop()
left=stack3.pop()
stack3.append(f(left,right))
return stack3.pop()
编辑:我感兴趣的真正问题是输入了一系列不同大小的张量,并且操作f解决了包含这些张量的线性程序并输出了一个新的张量。我不能简单地在初始数组上进行迭代,因为在这种情况下,f的输出大小呈指数增长。这就是为什么我使用这种分而治之的方法,从而减小了尺寸。递归程序可以很好地工作,但是对于大尺寸的程序,速度可能会显着降低,这可能是由于python打开并跟踪了框架。
答案 0 :(得分:0)
下面,我将程序转换为使用延续(then
)和蹦床(run
/ recur
)。它演化出一个线性的迭代过程,并且不会溢出堆栈。如果您没有遇到堆栈溢出问题,这对解决您的特定问题没有多大帮助,但是它可以教您如何简化分支计算。
此将法线函数转换为连续传递样式的过程可能是机械的。如果您稍稍斜视一下,您将看到该程序具有与您大多数相同的元素。内联注释并排显示代码-
import numpy as np
def identity (x):
return x
def recur (*values):
return (recur, values)
def run (f):
acc = f ()
while type (acc) is tuple and acc [0] is recur:
acc = f (*acc [1])
return acc
def myfunc (a):
# def recursive(w,i,j)
def loop (w = a, i = 0, j = len(a)-1, then = identity):
if i == j: # same
return then (w[i]) # wrap in `then`
else: # same
k = (j - i) // 2 + i # same
return recur \ # left=recursive(w,i,k)
( w
, i
, k
, lambda left:
recur # right=recursive(w,k+1,j)
( w
, k + 1
, j
, lambda right:
then # wrap in `then`
(f (left, right)) # same
)
)
return run (loop)
def f (a, b):
return a + b # same
a = np.random.rand(10) # same
print(a, myfunc(a)) # recursive(a, 0, a.shape[0]-1)
# [0.5732646 0.88264091 0.37519826 0.3530782 0.83281033 0.50063843 0.59621896 0.50165139 0.05551734 0.53719382]
# 5.208212213881435