试图理解python递归函数

时间:2016-05-04 20:26:29

标签: python algorithm recursion

我有以下片段,通过在“?”的位置更改0和1来精美地生成二进制数字。但我不明白这段代码是如何工作的。特别是 str_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??"))

关于如何编写这种递归函数的任何建议都会帮助我变得更好。

感谢您的时间。

2 个答案:

答案 0 :(得分:3)

函数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_list,则只打印出参数。

该行:

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 :(得分:3)

递归定义有两个部分:

  1. 终止条件。这部分很关键,经常首先出现。终止条件是你测试知道你是否“完成”。

    通常,递归函数具有某种“自然”终止条件。例如,当您返回到1时,Fibonacci序列结束。当您返回到1时,Factorials结束。当您获得空列表时,列表处理结束。字符串处理以空字符串结尾。

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

    出于这个原因,大多数递归函数看起来像这样:

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

    示例:

      

    N! := n *(n-1)!

         

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

         

    len(head:tail):= 1 + len(tail)

  3. 真实世界示例

    让我们来看看你的例子:

    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] = "?"没有做任何事情。我怀疑这段代码最近被修改过了。它可能会编辑str_list,直接将“0”和“1”设置为str_list[idx],而不是使用切片。

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