解释子集的创建与递归

时间:2018-12-12 23:33:28

标签: python recursion

在我的课堂上,我们讨论了递归创建子集的问题。尽管对链接功能的工作方式一无所知,但我在一定程度上理解了它:

   def subsets(nums):

    def helper(subset, i):
        if i == len(nums):
            res.append(subset[:])
        else:
            helper(subset, i+1)
            subset.append(nums[i])
            helper(subset, i+1)
            subset.remove(nums[i])

    res = []
    helper([], 0)
    return res

print(subsets(["a","b","c"]))

输出:

[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']]

2 个答案:

答案 0 :(得分:0)

我想说的是了解函数运行方式的最佳方法是在执行过程中跟踪其变量:

def subsets(nums):

    def helper(subset, i):
        print(  "|   "*i + "*"*90)
        print(  "|   "*i + "*{:^88}*".format("STARTING OF helper (i={})".format(i)))
        print(  "|   "*i + "*{:^88}*".format('res= {}, subset = {}'.format( res,subset,len(nums))))
        print(  "|   "*i + "*{:^88}*".format(' '))
        if i == len(nums):
            print( "|   "*i + "*{:^88}*".format('APPENDING "{}" to res'.format( (subset[:]))))
            res.append(subset[:])
        else:
            helper(subset, i+1)
            print( "|   "*i + "*{:^88}*".format('INTERMEDIATE STEP'.format( res)))
            print( "|   "*i + "*{:^88}*".format('APPENDING "{}" to subset'.format( nums[i])))
            subset.append(nums[i])
            helper(subset, i+1)
            print( "|   "*i + "*{:^88}*".format('INTERMEDIATE STEP'.format( res)))
            print( "|   "*i + "*{:^88}*".format('REMOVING "{}" from subset'.format( nums[i])))
            subset.remove(nums[i])

        print( "|   "*i + "*{:^88}*".format('res={}'.format( res)))
        print( "|   "*i + "*{:^88}*".format('END OF helper (i={})'.format( i)))
        print( "|   "*i + "*"*90)
        print( "|   "*i + " "*90)
        print( "|   "*i + " "*90)

    res = []
    helper([], 0)
    return res

print(subsets(["a","b","c"]))

将产生

******************************************************************************************
*                                STARTING OF helper (i=0)                                *
*                                  res= [], subset = []                                  *
*                                                                                        *
|   ******************************************************************************************
|   *                                STARTING OF helper (i=1)                                *
|   *                                  res= [], subset = []                                  *
|   *                                                                                        *
|   |   ******************************************************************************************
|   |   *                                STARTING OF helper (i=2)                                *
|   |   *                                  res= [], subset = []                                  *
|   |   *                                                                                        *
|   |   |   ******************************************************************************************
|   |   |   *                                STARTING OF helper (i=3)                                *
|   |   |   *                                  res= [], subset = []                                  *
|   |   |   *                                                                                        *
|   |   |   *                                 APPENDING "[]" to res                                  *
|   |   |   *                                        res=[[]]                                        *
|   |   |   *                                  END OF helper (i=3)                                   *
|   |   |   ******************************************************************************************
|   |   |                                                                                             
|   |   |                                                                                             
|   |   *                                   INTERMEDIATE STEP                                    *
|   |   *                                APPENDING "c" to subset                                 *
|   |   |   ******************************************************************************************
|   |   |   *                                STARTING OF helper (i=3)                                *
|   |   |   *                               res= [[]], subset = ['c']                                *
|   |   |   *                                                                                        *
|   |   |   *                                APPENDING "['c']" to res                                *
|   |   |   *                                    res=[[], ['c']]                                     *
|   |   |   *                                  END OF helper (i=3)                                   *
|   |   |   ******************************************************************************************
|   |   |                                                                                             
|   |   |                                                                                             
|   |   *                                   INTERMEDIATE STEP                                    *
|   |   *                                REMOVING "c" from subset                                *
|   |   *                                    res=[[], ['c']]                                     *
|   |   *                                  END OF helper (i=2)                                   *
|   |   ******************************************************************************************
|   |                                                                                             
|   |                                                                                             
|   *                                   INTERMEDIATE STEP                                    *
|   *                                APPENDING "b" to subset                                 *
|   |   ******************************************************************************************
|   |   *                                STARTING OF helper (i=2)                                *
|   |   *                            res= [[], ['c']], subset = ['b']                            *
|   |   *                                                                                        *
|   |   |   ******************************************************************************************
|   |   |   *                                STARTING OF helper (i=3)                                *
|   |   |   *                            res= [[], ['c']], subset = ['b']                            *
|   |   |   *                                                                                        *
|   |   |   *                                APPENDING "['b']" to res                                *
|   |   |   *                                 res=[[], ['c'], ['b']]                                 *
|   |   |   *                                  END OF helper (i=3)                                   *
|   |   |   ******************************************************************************************
|   |   |                                                                                             
|   |   |                                                                                             
|   |   *                                   INTERMEDIATE STEP                                    *
|   |   *                                APPENDING "c" to subset                                 *
|   |   |   ******************************************************************************************
|   |   |   *                                STARTING OF helper (i=3)                                *
|   |   |   *                      res= [[], ['c'], ['b']], subset = ['b', 'c']                      *
|   |   |   *                                                                                        *
|   |   |   *                             APPENDING "['b', 'c']" to res                              *
|   |   |   *                           res=[[], ['c'], ['b'], ['b', 'c']]                           *
|   |   |   *                                  END OF helper (i=3)                                   *
|   |   |   ******************************************************************************************
|   |   |                                                                                             
|   |   |                                                                                             
|   |   *                                   INTERMEDIATE STEP                                    *
|   |   *                                REMOVING "c" from subset                                *
|   |   *                           res=[[], ['c'], ['b'], ['b', 'c']]                           *
|   |   *                                  END OF helper (i=2)                                   *
|   |   ******************************************************************************************
|   |                                                                                             
|   |                                                                                             
|   *                                   INTERMEDIATE STEP                                    *
|   *                                REMOVING "b" from subset                                *
|   *                           res=[[], ['c'], ['b'], ['b', 'c']]                           *
|   *                                  END OF helper (i=1)                                   *
|   ******************************************************************************************
|                                                                                             
|                                                                                             
*                                   INTERMEDIATE STEP                                    *
*                                APPENDING "a" to subset                                 *
|   ******************************************************************************************
|   *                                STARTING OF helper (i=1)                                *
|   *                  res= [[], ['c'], ['b'], ['b', 'c']], subset = ['a']                   *
|   *                                                                                        *
|   |   ******************************************************************************************
|   |   *                                STARTING OF helper (i=2)                                *
|   |   *                  res= [[], ['c'], ['b'], ['b', 'c']], subset = ['a']                   *
|   |   *                                                                                        *
|   |   |   ******************************************************************************************
|   |   |   *                                STARTING OF helper (i=3)                                *
|   |   |   *                  res= [[], ['c'], ['b'], ['b', 'c']], subset = ['a']                   *
|   |   |   *                                                                                        *
|   |   |   *                                APPENDING "['a']" to res                                *
|   |   |   *                       res=[[], ['c'], ['b'], ['b', 'c'], ['a']]                        *
|   |   |   *                                  END OF helper (i=3)                                   *
|   |   |   ******************************************************************************************
|   |   |                                                                                             
|   |   |                                                                                             
|   |   *                                   INTERMEDIATE STEP                                    *
|   |   *                                APPENDING "c" to subset                                 *
|   |   |   ******************************************************************************************
|   |   |   *                                STARTING OF helper (i=3)                                *
|   |   |   *            res= [[], ['c'], ['b'], ['b', 'c'], ['a']], subset = ['a', 'c']             *
|   |   |   *                                                                                        *
|   |   |   *                             APPENDING "['a', 'c']" to res                              *
|   |   |   *                 res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c']]                  *
|   |   |   *                                  END OF helper (i=3)                                   *
|   |   |   ******************************************************************************************
|   |   |                                                                                             
|   |   |                                                                                             
|   |   *                                   INTERMEDIATE STEP                                    *
|   |   *                                REMOVING "c" from subset                                *
|   |   *                 res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c']]                  *
|   |   *                                  END OF helper (i=2)                                   *
|   |   ******************************************************************************************
|   |                                                                                             
|   |                                                                                             
|   *                                   INTERMEDIATE STEP                                    *
|   *                                APPENDING "b" to subset                                 *
|   |   ******************************************************************************************
|   |   *                                STARTING OF helper (i=2)                                *
|   |   *      res= [[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c']], subset = ['a', 'b']       *
|   |   *                                                                                        *
|   |   |   ******************************************************************************************
|   |   |   *                                STARTING OF helper (i=3)                                *
|   |   |   *      res= [[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c']], subset = ['a', 'b']       *
|   |   |   *                                                                                        *
|   |   |   *                             APPENDING "['a', 'b']" to res                              *
|   |   |   *           res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b']]            *
|   |   |   *                                  END OF helper (i=3)                                   *
|   |   |   ******************************************************************************************
|   |   |                                                                                             
|   |   |                                                                                             
|   |   *                                   INTERMEDIATE STEP                                    *
|   |   *                                APPENDING "c" to subset                                 *
|   |   |   ******************************************************************************************
|   |   |   *                                STARTING OF helper (i=3)                                *
|   |   |   *res= [[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b']], subset = ['a', 'b', 'c']*
|   |   |   *                                                                                        *
|   |   |   *                           APPENDING "['a', 'b', 'c']" to res                           *
|   |   |   *   res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']]   *
|   |   |   *                                  END OF helper (i=3)                                   *
|   |   |   ******************************************************************************************
|   |   |                                                                                             
|   |   |                                                                                             
|   |   *                                   INTERMEDIATE STEP                                    *
|   |   *                                REMOVING "c" from subset                                *
|   |   *   res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']]   *
|   |   *                                  END OF helper (i=2)                                   *
|   |   ******************************************************************************************
|   |                                                                                             
|   |                                                                                             
|   *                                   INTERMEDIATE STEP                                    *
|   *                                REMOVING "b" from subset                                *
|   *   res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']]   *
|   *                                  END OF helper (i=1)                                   *
|   ******************************************************************************************
|                                                                                             
|                                                                                             
*                                   INTERMEDIATE STEP                                    *
*                                REMOVING "a" from subset                                *
*   res=[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']]   *
*                                  END OF helper (i=0)                                   *
******************************************************************************************


[[], ['c'], ['b'], ['b', 'c'], ['a'], ['a', 'c'], ['a', 'b'], ['a', 'b', 'c']]

要获得更深入的说明,您将看到的帮助程序将从0级的空列表开始执行。

对于每个低于len(nums)的辅助函数级别,递归函数将分支为2个新的递归函数,该函数将保留子集不变或将nums的第i个元素添加到其中。

对于最后一个级别,将把子集添加到结果中,并可以通过一些ascii艺术图轻松地对其进行可视化

nums = ['a','b','c']
level:   0='a'   1='b'     2='c'         3=add_to_res
         [] ---> [] -----> [] ---------> []
          |       |         |__________> ['c']
          |       |
          |       |______> ['b'] ------> ['b']
          |                 |__________> ['b','c']
          |
          |____> ['a'] --> ['a'] ------> ['a']
                    |       |__________> ['a','c']
                    |
                    |____> ['a','b'] --> ['a','b']
                            |__________> ['a','b','c']

从面向数学的角度出发,您可以考虑从上一次迭代开始:

  • 对[[],'c']与[[],'b'] = [[],'b','c',['b','c']]进行交叉生产
  • 比取[[],'a'] = [[],['c'],['b'],['b','c'],[']的结果的叉积a'],['a','c'],['a','b'],['a','b','c']]

答案 1 :(得分:0)

我将只讨论两个函数的关系,而不是递归算法。

内部函数helper是主例程,外部函数subsets只是为内部函数设置了参数。让我们用更明确的变量名和稍作更改来重写此函数:

def subsets(elements):
    result = []

    def subsets_recursive(subset, index):
        if index == len(elements):
            result.append(subset[:])
        else:
            subsets_recursive(subset, index + 1)
            subset.append(elements[index])
            subsets_recursive(subset, index + 1)
            del subset[-1]

    subsets_recursive([], 0)

    return result

print(subsets(['a', 'b', 'c']))

我用del subset[-1]代替了subset.remove(nums[i]),因为remove()意味着要进行搜索,但是我们知道我们在subsets列表的末尾添加了新元素,并且仍然存在需要删除它时。 (即效率。)

现在,让我们重新编写代码以消除外部函数:

def subsets_recursive(elements, subset=[], index=0):  # dangerous default value
    result = []

    if index == len(elements):
        result.append(subset[:])
    else:
        result.extend(subsets_recursive(elements, subset, index + 1))
        subset.append(elements[index])
        result.extend(subsets_recursive(elements, subset, index + 1))
        del subset[-1]

    return result

print(subsets_recursive(['a', 'b', 'c']))

尽管subset=[]被认为是一个危险的默认值(是一个容器),但在这种情况下,由于放入subset中的任何东西都被再次取出, if 一切正常完成,因此可以在下次通话时使用。虽然这是一个很大的 if

要摆脱 dangerous 的默认设置,并向例程的用户隐藏我们不希望设置的两个额外参数,我们将其包装在一个非递归例程中,该例程仅接受一个参数,并以所需方式在内部设置调用。这使我们回到了开始的地方,但是这次实现了我可能做的方式:

def subsets(elements):

    def subsets_recursive(subset, index):
        result = []

        if index == len(elements):
            result.append(subset[:])
        else:
            result.extend(subsets_recursive(subset, index + 1))
            subset.append(elements[index])
            result.extend(subsets_recursive(subset, index + 1))
            del subset[-1]

        return result

    return subsets_recursive([], 0)

print(subsets(['a', 'b', 'c']))

相对于副作用,我更喜欢适当的return通话。