递归函数中的计数器

3
我是新手,对Python和编程一般不太熟悉。我写了一个函数,可以搜索数组中相邻的元素,并查找值在0.05之内的元素,这有点像泛洪算法。唯一的区别是,在计算函数运行次数(我认为这也会告诉我找到多少个元素)时,我做了一些愚蠢的事情,所以我的计数器值是错误的。代码在查找0.05范围内的相邻元素方面是有效的,只是计数有些问题。
def floodcount (x,y,array,value,count=0):     #akin to a bucket fill in paint, finds the area instead

    nrows = len(array)-1          #rows of the image
    ncols = len(array[0])-1       #columns of the image
    diff = array[x][y] - value
    if (diff < 0.00) or (diff > 0.05): # the base case, finding a diff more than 0.05 or less than 0 is like finding a boundary
        return 0

    count = count +1
    print 'count1 ',count

    array[x][y] = -5 # so we do no calculate this pixel again
    #print "[",x,",",y,"]"
    if x > 0:
        #print '1'# if not the first elemnet then can go back, this makes sure that x is within the array all the time
        floodcount (x-1,y,array,value,count)
    if y > 0:
        #print '2'
        floodcount (x,y-1,array,value,count) 
    if x < nrows:
        #print '3'
        floodcount (x+1,y,array,value,count)
    if y < ncols:
        #print '4'
        floodcount (x,y+1,array,value,count)
    if x > 0 and y > 0:
        #print '5'
        floodcount (x-1,y-1,array,value,count)
    if x < nrows and y < ncols:
        #print '6'
        floodcount (x+1,y+1,array,value,count)
    if x <nrows and y > 0:
        #print '7'
        floodcount (x+1,y-1,array,value,count)
    if x > 0 and y < ncols:
        #print '8'
        floodcount (x-1,y+1,array,value,count)

    print 'count2 ',count    
    return count

因此,对于一个测试用例

数组 = [[5,1,1,3,4],[4,5,6,2,5],[5,8,5,5,9]] x=0 和 y=0

输出

count1 1 count1 2 count1 3 count1 4 count1 5 count2 5 count2 4 count2 3 count1 3 count2 3 count2 2 count2 1

正如你所看到的,有些可疑 :P 有人能指出我做错了什么吗?任何帮助将不胜感激。


我认为nrows和ncols应该被重新命名,因为它们实际上并没有存储行数和列数(当我尝试回答时,我感到困惑)。从它们的初始化中删除-1,并更改您的if语句逻辑。 - colithium
5个回答

3
所以floodcount()函数返回新的count值。但你从未将其存储或使用 :)

请将以下行替换为:

floodcount(x+1, y-1, array, value, count)

随着:

count = floodcount(x+1, y-1, array, value, count)

我认为你想把 return 0 改成 return counterif (diff < 0.00) or (diff > 0.05) 中。 - Cwt

2
您获得的结果是预期的。
更新:我的解释(如下)并不完全正确。(感谢Ben的启示)。(然而,我的解决方案建议是正确的)
计数参数通过值传递到递归调用中,而不是通过引用。这意味着您在子调用中进行的递增对当前函数中的计数变量(即局部函数变量)没有影响。
您可以通过使用全局变量来实现所需的结果。
count = 0
def floodcount (x,y,array,value):
    global count
    ...

或者在包装类中使用计数器(对象通过引用传递):

class CounterClass:
    cnt = 0

def floodcount (x,y,array,value, counter):
    ...
    counter.cnt += 1
    ...

否则:返回你的函数产生的计数器。
count = floodcount(x+1, y-1, array, value, count)

1
这并不是严格意义上的真实情况。在Python中,一切都是按引用传递的。只是count += 1不会修改count所引用的对象(当count是整数时),它会创建一个新的整数,然后将count绑定到该整数上。因此,与所有名称绑定一样,它只在本地作用域中产生影响,而不会对任何其他引用相同事物的count产生影响。这是因为你无法修改整数,只能通过旧整数上的操作创建新的整数对象。 - Ben
好的。谢谢你的启示。 - gecco
+1 是指向引用/值(可变/不可变)的,我认为这可能是 OP 不理解的问题。 - warvariuc

2
除了现在已经解决的计数问题之外:
您可以通过每次进行所有递归调用并在函数开头使用if x < 0 or y < 0 or x > nrows or y > ncols检查数组边界来减少if语句的数量。
#akin to a bucket fill in paint, finds the area instead
def floodcount (x,y,array,value,count=0): 
    nrows = len(array)-1          #rows of the image
    ncols = len(array[0])-1       #columns of the image
    if x < 0 or y < 0 or x > nrows or y > ncols:
        return count

    diff = array[x][y] - value
    # the base case, finding a diff more than 0.05 or less than 0 is like finding a boundary
    if (diff < 0.00) or (diff > 0.05): 
        return count

    count = count +1
    print 'count1 ',count

    array[x][y] = -5 # so we do no calculate this pixel again
    #print "[",x,",",y,"]"

    count = floodcount (x-1,y,array,value,count)
    count = floodcount (x,y+1,array,value,count)
    count = floodcount (x+1,y,array,value,count)
    count = floodcount (x,y-1,array,value,count)

    count = floodcount (x-1,y-1,array,value,count)
    count = floodcount (x+1,y+1,array,value,count)
    count = floodcount (x+1,y-1,array,value,count)
    count = floodcount (x-1,y+1,array,value,count)

    print 'count2 ',count    
    return count

1
你需要递归调用 floodcount 函数,并将当前的 count 作为参数传入,函数会返回它完成时的 count 值。然后你忽略了这个返回值,继续使用相同的 count 参数进行下一次递归调用。尝试将所有的递归调用改为 count = floodcount(...)

我尝试过了,但它的输出是:count1 1 count1 1 count1 1 count1 1 count1 1 count2 0 count2 0 count2 0 count1 1 count2 0 count2 0 count2 0但将count声明为全局变量可以正常工作(就像gecco建议的那样)。然而,根据您之前在Gecco帖子中的评论,似乎这并不是预期的结果?有什么建议,还是应该坚持现有的方法? - Elegant_Cow
@Elegant_Cow:如果您需要调用此函数超过一次并且忘记将全局变量重置为0,则全局变量将失败。您确定在尝试我的建议时仍然传递了计数吗? - Ben
现在可以工作了,非常感谢。现在我知道全局变量的陷阱了 :) - Elegant_Cow

0
如果xy都大于0,你将运行floodcount()两次。这是你想要的吗?看起来你只想在数组中的每个元素上运行一次floodcount。如果是这样,请修改你的代码使用if/elif而不是仅仅使用if
if x > 0:
    floodcount (x-1,y,array,value,count)
elif y > 0:
    floodcount (x,y-1,array,value,count) 

#elif all the rest

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接