微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将递归算法变成迭代算法

如何解决如何将递归算法变成迭代算法

我写了这个算法,但我真的不知道是否可以将其转换为迭代算法。我正在尝试获取立方体形状的每个节点的邻接节点。相邻节点必须满足两个条件:

  1. 这是一个灰色节点。
  2. 它在 distance 的半径内

def find_continumm(seed,node,row,gray,xyz,distance):
"""
seed: the nodes we want to find the adjacent nodes for. 
node: the candidate nodes to be in the adjacency.
row:  save the nodes that are adjacent. 
gray: boolean array that tells if a node is a gray or not. 
xyz: the 3 dim of the shape. 
distance: the radius
"""
    node_ravel = np.ravel_multi_index(node,xyz)
    if node_ravel in row or ~gray[node_ravel] or math.dist(node,seed) > distance:
        return
    row.add(node_ravel)
    if node[0] < xyz[0]:
        node[0] = node[0] + 1
        find_continumm(seed,distance)
        node[0] = node[0] - 1
    if node[0] > 0:
        node[0] = node[0] - 1
        find_continumm(seed,distance)
        node[0] = node[0] + 1
    if node[1] < xyz[1]:
        node[1] = node[1] + 1
        find_continumm(seed,distance)
        node[1] = node[1] - 1
    if node[1] > 0:
        node[1] = node[1] - 1
        find_continumm(seed,distance)
        node[1] = node[1] + 1
    if node[2] < xyz[2]:
        node[2] = node[2] + 1
        find_continumm(seed,distance)
        node[2] = node[2] - 1
    if node[2] > 0:
        node[2] = node[2] - 1
        find_continumm(seed,distance)
        node[2] = node[2] + 1

解决方法

是的,总是可以将递归算法变成迭代算法。执行此操作的一般程序是切换到 continuation passing style,应用 defunctionalization,然后应用 tail-call elimination。这三个转换的组合将把一个递归函数变成一个迭代函数,可能需要一个堆栈。

在将其应用到您的代码之前,我将简要地重写您的代码如下:

def find_continumm(seed,node,row,gray,xyz,distance):
    def helper():
        node_ravel = np.ravel_multi_index(node,xyz)
        if node_ravel in row or ~gray[node_ravel] or math.dist(node,seed) > distance:
            return
        row.add(node_ravel)
        for i in range(3):
            if node[i] < xyz[i]:
                node[i] += 1
                helper()
                node[i] -= 1
            if node[i] > 0:
                node[i] -= 1
                helper()
                node[i] += 1
    helper()

您可以亲眼看到,这与您的代码版本相同。我将进行最后一次重写以使用 while 循环而不是 for 循环:

def find_continumm(seed,seed) > distance:
            return
        row.add(node_ravel)
        i = 0
        while i < 3:
            if node[i] < xyz[i]:
                node[i] += 1
                helper()
                node[i] -= 1
            if node[i] > 0:
                node[i] -= 1
                helper()
                node[i] += 1
            i += 1
    helper()

这极大地简化了代码,并使将其转换为迭代版本变得更加简单。

最终的迭代版本是:

beginning = 0
entering_loop = 1
finishing_first_call = 2
enter_second_if = 3
finishing_second_call = 4
increment_i = 5
# the actual values of the above variables don't matter
# so long as they're different

def find_continumm(seed,distance):
    stack = []
    add_to_stack = lambda tag,data : stack.append((tag,data))
    back_to_beginning = lambda : add_to_stack(beginning,None)
    back_to_beginning()
    while stack:
        tag,i = stack.pop()
        
        if tag is beginning:
            node_ravel = np.ravel_multi_index(node,xyz)
            if node_ravel in row or ~gray[node_ravel] or math.dist(node,seed) > distance:
                pass
            else:
                row.add(node_ravel)
                add_to_stack(entering_loop,0)
                
        elif tag is entering_loop:
            if i < 3:
                if node[i] < xyz[i]:
                    node[i] += 1
                    add_to_stack(finishing_first_call,i)
                    back_to_beginning()
                else:
                    add_to_stack(enter_second_if,i)
                
        elif tag is finishing_first_call:
            node[i] -= 1
            add_to_stack(enter_second_if,i)
            
        elif tag is enter_second_if:
            if node[i] > 0:
                node[i] += 1
                add_to_stack(finishing_second_call,i)
                back_to_beginning()
            else:
                add_to_stack(increment_i,i)
                
        elif tag is finishing_second_call:
            node[i] -= 1
            add_to_stack(increment_i,i)
            
        elif tag is increment_i:
            add_to_stack(entering_loop,i + 1)  

如果您查看迭代版本,您会注意到它与带有 while 循环的递归版本非常接近。每个标签对应于这个递归版本中我们“跳回”的特定代码行。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。