试图理解python递归函数

试图理解python递归函数,python,algorithm,recursion,Python,Algorithm,Recursion,我有下面的代码片段,它通过在“?”处更改0和1漂亮地生成二进制数。但我不明白这段代码是如何工作的。尤其是行stru list[idx]=“?”。为什么“?”开始恢复到idx位置 在编写递归时应该如何考虑这一点 这是密码 def gen_bin(str_list): if "?" not in str_list: print "".join(str_list) return idx = str_list.index("?") gen_bin

我有下面的代码片段,它通过在“?”处更改0和1漂亮地生成二进制数。但我不明白这段代码是如何工作的。尤其是行stru list[idx]=“?”。为什么“?”开始恢复到idx位置

在编写递归时应该如何考虑这一点

这是密码

def gen_bin(str_list):
    if "?" not in str_list:
        print "".join(str_list)
        return

    idx = str_list.index("?")
    gen_bin(str_list[:idx] + ["0"] + str_list[idx+1:])
    gen_bin(str_list[:idx] + ["1"] + str_list[idx+1:])

    str_list[idx] = "?"


gen_bin(list("1??"))
任何关于如何编写此类递归函数的建议都将帮助我变得更好

感谢您的时间。

函数
gen_bin()
只需在输入参数列表中查找第一个出现的
,如下所示:

idx = str_list.index("?")
然后只需在该位置插入
0
,并将该新列表作为新参数递归运行:

gen_bin(str_list[:idx] + ["0"] + str_list[idx+1:])
然后在那里插入
1
,并再次递归运行:

gen_bin(str_list[:idx] + ["1"] + str_list[idx+1:])
如果
str_列表中没有
,它只打印出参数

该行:

str_list[idx] = "?"
是不必要的,并且完全不执行任何操作,您可以在运行以下代码时观察到这一点:

def gen_bin(str_list):
    if "?" not in str_list:
        #print "".join(str_list)
        return

    idx = str_list.index("?")
    gen_bin(str_list[:idx] + ["0"] + str_list[idx+1:])
    gen_bin(str_list[:idx] + ["1"] + str_list[idx+1:])

    print str_list
    str_list[idx] = "?"
    print str_list

gen_bin(list("1??"))
返回:

['1', '0', '?']
['1', '0', '?']
['1', '1', '?']
['1', '1', '?']
['1', '?', '?']
['1', '?', '?']

递归定义分为两部分:

  • 终止条件。这一部分很关键,经常首先出现。终止条件是您测试以了解是否“完成”

    通常,递归函数具有某种“自然”终止条件。例如,当返回到1时,斐波那契序列结束。当你回到1时,阶乘结束。当您得到一个空列表时,列表处理结束。字符串处理以空字符串结束

    不管它是什么,任何递归函数都会失败——通常是通过循环或无限递归直到堆栈溢出发生——除非您正确定义了终止条件,并且成功地检查了它

    因此,大多数递归函数如下所示:

    def recursive_func(arg):
        if terminating_condition(arg):
            return simplest_value
    
        # more code here
        recursive_func(reduced_form(arg))
    
  • 递归关系。一旦检查(并失败)终止条件的测试,就必须调用递归关系。一般来说,这意味着执行一个涉及相同递归函数的较小形式的计算

    示例:

    n!:=n*(n-1)

    fib(n):=fib(n-1)+fib(n-2)

    长度(头部:尾部):=1+长度(尾部)

  • 真实世界示例

    让我们看一下您的示例:

    def gen_bin(str_list):
        if "?" not in str_list:
            print "".join(str_list)
            return
    
        idx = str_list.index("?")
        gen_bin(str_list[:idx] + ["0"] + str_list[idx+1:])
        gen_bin(str_list[:idx] + ["1"] + str_list[idx+1:])
    
        str_list[idx] = "?"
    
    gen_bin(list("1??"))
    
    很明显,这个函数遵循经典结构。第一段是对终止条件的测试。在这种情况下,终止条件是字符串中没有要替换的“?”

    函数的其余部分专用于递归关系。在本例中,这包括用“0”或“1”替换字符串中第一个出现的“?”并递归

    我认为这不是很好的代码。首先,结尾的赋值,
    str_list[idx]=“?”
    ,没有任何作用。我怀疑这段代码最近被修改过。它可能就地编辑了
    stru列表
    ,将“0”和“1”设置为
    stru列表[idx]
    ,而不是使用切片


    不过,更重要的是,这不是一个好代码,因为它所做的只是打印结果。如果它返回一个二进制字符串列表,而不是试图打印它们,那将是一个更好的函数。

    感谢您的详细解释。我看到这行代码没有做任何事情。这段代码进行2次递归调用。一个带0,另一个带1。如何修改同一个函数以在一行或一次调用中调用两个次递归函数。这取决于您尝试执行的操作。可能最简单的方法是列举这两个:
    call('0')、call('1')
    谢谢你给我解释。你是对的。那行代码什么都没做。现在,我如何将我们在函数内部进行的两个递归调用(一个插入0,另一个插入1)组合成一个递归调用?我不明白,为什么要组合这两个调用?