Python递归错误 - RangeError:超出最大调用堆栈大小

时间:2014-12-08 17:05:20

标签: python list recursion multidimensional-array

使用Python 2.7,我试图编写代码以递归方式替换二维列表的元素。以下是该函数的代码片段:

import sys
sys.setrecursionlimit(10000)

def assimilate(population, x, y, influence):
    """Replace adjacent list elements recursively with -1 if cell is 
    lesser than the adjacent influenced cell.

    Keyword arguments:
    population -- 2D list of integers
    x -- x-coordinate of influencing cell
    y -- y-coordinate of influencing cell
    influence -- value of influencing cell

    Returns:
    Modified population list.
    """

    if population[y][x] <= influence:
        population[y][x] = -1
    if population[y][x] == -1:
        # Check adjacent cells
        if y - 1 > 0:
            if population[y - 1][x] <= influence:
                population = assimilate(population, y - 1, x, influence)
        if x + 1 < len(population):
            if population[y][x + 1] <= influence:
                population = assimilate(population, y , x + 1, influence)
        if y + 1 < len(population):
            if population[y + 1][x] <= influence:
                population = assimilate(population, y + 1, x, influence)
        if x - 1 > 0:
            if population[y][x - 1] <= influence:
                population = assimilate(population, y, x - 1, influence)
    return population

如果代码的值小于或等于-1的值,则代码的目标是将相邻的列表元素(向上,向下,向左和向右,没有对角线)替换为influence。它需要迭代,直到范围内所有可能的单元格都被转换。

这方面的一个例子是:

In: assimilate([[0, 1, 2], [8, 4, 5], [6, 7, 3]], 0, 0, 5)
Out: [[-1, -1, -1], [8, -1, -1], [6, 7, -1]]
Out (as a 2D list, visualized):
-1 -1 -1
8 -1 -1
6 7 -1

使用代码,输入5到influence会导致输出错误,并且增加influence的值会导致RuntimeError: maximum recursion depth exceeded(通过添加import sys和{ {1}}或sys.setrecursionlimit(10000)

三个问题:

  • 如何实现递归有什么问题?
  • 在检查相邻值时是否有更好的方法来遍历列表?
  • 错误的可能解决方案是什么?

递归不是强制性的,可以使用其他替代方案。我尝试使用Internal error: RangeError: Maximum call stack size exceeded循环,但仍然输出错误。我尽量不要使用第三方软件包。

1 个答案:

答案 0 :(得分:0)

这不是Python的问题,而是一个逻辑错误。

此处(以及其他类似地方)的逻辑存在问题,

  

如果人口[y] [x] <=影响:

    population[y][x] = -1

让我们说,

  

人口[3] [2] = -1

。现在,在递归过程中,当程序来到

  

种群[3] [1],它将看到它的相邻细胞&gt; (人口[3] [2])

小于影响值。如果影响是积极的,那将永远是真的。因此它将再次转向&gt;已经访问过一次的人口[3] [2]小区。因此递归调用将变为无限。

要检查此项,您可以更改以下行:

  

如果人口[y] [x]&lt; =影响和人口[y] [x]!= -1:           人口[y] [x] = -1

请知道此解决方案是否有效。您必须在if条件的每个位置更改此逻辑

编辑(带更正)

当它访问一个单元格并使其为-1时,它将不会再次进入该单元格并将停止递归。我实现了这个并且递归停止了。但这也是一个问题。如果有效为-1的单元格被高于影响的值包围,则永远不会访问它。

请考虑以下示例:

influence=5

[ 9, 9, 2 ]
[ 9, 9, 9 ]
[ 9, 9, 9 ]

在此示例中,如果仅检查-1,则永远不会访问2的单元格。因为,2被9包围,9将永远不会被-1替换。

为了解决这个问题,我们需要另一个能够跟踪访问的数组。该数组将初始化为0.如果已访问某个单元格,则其值将为1,并且永远不会重新访问访问的单元格。

检查以下代码。工作正常。

import sys
def assimilate(population, visited, y, x, influence):
    visited[y][x] = 1

    if population[y][x] <= influence:
        population[y][x] = -1
        # Check adjacent cells
        if y - 1 >= 0:
            if visited[y - 1][x] != 1:
                population = assimilate(population, visited , y - 1, x, influence)

        if x + 1 < len(population):
            if visited[y][x + 1] != 1:
                population = assimilate(population, visited ,  y , x + 1, influence)

        if y + 1 < len(population):
            if visited[y + 1][x] != 1:
                population = assimilate(population, visited ,  y + 1, x, influence)

        if x - 1 >= 0:
            if visited[y][x - 1] != 1:
                population = assimilate(population, visited ,  y, x - 1, influence)

    return population

print assimilate( [[0, 1, 2], [8, 4, 5], [6, 7, 3]] , [[0,0,0],[0,0,0],[0,0,0]] , 0 , 0 , 5 )

<强>输出:

[[-1, -1, -1], [8, -1, -1], [6, 7, -1]]