递归导致不必要的循环

时间:2015-01-08 21:30:24

标签: python loops recursion

我在使用递归方面遇到了一些困难。下面,我有一段试图解决难题的代码。 process()生成排列,然后solve()遍历这些排列并检查每个排列。如果解决方案在某个位​​置失败,则该函数将删除以相同方式开始的所有可能解决方案,并以递归方式重新运行。 test_it()函数在solve()中调用,作为确定解决方案何时不正确的方法。

这最终给出了正确的结果,但是当我添加了打印行时:

print 'Fail', combo, count           

我注意到它的功能似乎识别出正确的解决方案,但无论如何都会继续迭代。我想我可能会搞乱嵌套循环,因为一旦到达这一行:

return combo

它没有终止。

import itertools

final_side = [{(1,2): [[1,0,1,1]]},\
              {(2,1): [[1,1,0,1]]},\
              {1: [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]},\
              {1: [[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]]}]

final_top = [{2: [[1,1,0,0],[0,1,1,0],[0,0,1,1]]},\
              {(1,1): [[1,0,1,0],[1,0,0,1],[0,1,0,1]]},\
              {(1,1): [[1,0,1,0],[1,0,0,1],[0,1,0,1]]},\
              {2: [[1,1,0,0],[0,1,1,0],[0,0,1,1]]}]

def process():
    # Generates all permutations
    possible = []
    possibilities = []
    a = []

    for dic in final_side:
        for values in dic.values():
            possible.append(len(values))            

    for number in possible:
        a.append([x for x in range(number)])

    b = map(list, itertools.product(*a))

    return b

def test_it(listx, final_top, final_side):

    length = len(listx)
    place = []    

    if length > 0:
        pot = map(list, zip(*listx))
        for j in range(len(pot)):
            x = final_top[j].values()[0]
            test = [x[i][:length] for i in range(len(x))]

            if pot[j] not in test:
                return False

            else:
                loc = [x for x,val in enumerate(test) if val== pot[j]]
                place.append(loc)
    return place


def solve(listx):

    solution = []     

    for combo in listx[:]:
        pos = -1
        temp = []
        count = 0
        for num in combo:
            pos += 1
            temp.append(final_side[pos].values()[0][num])
            place = test_it(temp, final_top, final_side)    

            if place == False:
                blah = combo[:pos+1]
                listx = [x for x in listx if not x[:pos+1] == combo[:pos+1]]
                print 'Fail', combo, count                 
                solve(listx)

            else:
                count += 1
                if count == 4:
                    return combo

def main():


    a = process()
    solution = solve(a)

    print solution

main()

1 个答案:

答案 0 :(得分:2)

您忽略了递归调用的返回值:

if place == False:
    blah = combo[:pos+1]
    listx = [x for x in listx if not x[:pos+1] == combo[:pos+1]]
    print 'Fail', combo, count                 
    solve(listx)

solve()调用的返回值被删除;它不会被传递给下一个调用者,也不会在那里结束循环。

添加return以退出递归调用的级别:

if not place:
    blah = combo[:pos+1]
    listx = [x for x in listx if not x[:pos+1] == combo[:pos+1]]
    print 'Fail', combo, count                 
    return solve(listx)

我还用place == False替换not place,这是一种更好的测试布尔值假的方法。

通过这些更改,您的脚本输出:

$ bin/python test.py 
Fail [0, 0, 0, 0] 2
Fail [0, 0, 1, 0] 2
Fail [0, 0, 2, 0] 3
[0, 0, 2, 1]