【发布时间】:2019-06-12 19:07:48
【问题描述】:
我想将数组上的递归算法转换为迭代函数。它不是尾递归算法,并且有两个递归调用,然后是一些操作。 该算法是一种分而治之的算法,其中在每一步将数组拆分为两个子数组,并将某个函数 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 打开并跟踪的帧。
【问题讨论】:
-
通常使用堆栈,这就是递归使用调用堆栈所做的事情。在这种特定情况下,请使用
sum。我相信做到这一点的好方法需要了解递归算法的作用并使用迭代从头开始重新设计。所以答案需要查看您的实际算法。 -
使用“私有”堆栈不会将您的程序转换为迭代程序(至少纯迭代,取决于迭代的定义),它只是一种欺骗和呈现递归程序的方式到迭代程序之一。
-
顺便说一句,你真的不需要导入 numpy 来做整数除法。只需
k = (j + i) // 2。 -
谢谢我已经修改了这个并扩展了我感兴趣的实际算法。
标签: python algorithm recursion dynamic-programming divide-and-conquer