子集树

最近上班上到脑袋都晕,,,突然想到要复习一下。就搞了个子集树的代码。。

 

其实子集树有点像暴力破解,大名鼎鼎的0-1规划中的背包问题一样。假设有N个背包,对应N个元素。

那么有:

         背包                   1                   2                   3                   ...                   n         
        要/不要       要/不要       要/不要       要/不要       要/不要       要/不要

然后要、不要分别对两种情况,好比二叉树的左子树和右子树一样。

 

子集树写法也参考了背包问题,遍历N个背包,分别决定要不要该背包,然后遍历整棵树。

  当发现遍历层数满了以后,就打印路径即可~

if num == len(arr):
    outputList.append([arr[index] for index in range(0, num) if cur_arr[index] ])
    return

     当层数未满,那么继续尝试

    1、要该背包

    2、不要该背包

   对应代码:

    # 选第num个元素
    cur_arr[num] = 1
    subSetTree(arr, cur_arr, num + 1, outputList)
    # 不选第num 个元素
    cur_arr[num] = 0
    subSetTree(arr, cur_arr, num + 1, outputList)

 那么问题来了,如果将该元素append进一个数组中,然后执行完了再弹出可以吗?

  【不可以】原理很简单,这个子集树肯定遍历该树的所有路径,如果往里面append元素,那么必然会涉及到重复添加元素。。。必然涉及到处理以后情况

    1、某一路径到头了,可能回头走若干步,然后再继续往下走。。。这时候涉及的问题就巨复杂了。。。

    2、由于递归之后,数组中的元素大小已经发生了变化,这时候如果使用

                    cur_arr[num] = cur_arr[:-1]
      会导致修改错数据。。。。
3、反正这种处理是巨恶心的。。。

 

def subSetTree(arr, cur_arr, num, outputList):
    if num == len(arr):
        outputList.append([arr[index] for index in range(0, num) if cur_arr[index] ])
        return

    # 选第num个元素
    cur_arr[num] = 1
    subSetTree(arr, cur_arr, num + 1, outputList)
    # 不选第num 个元素
    cur_arr[num] = 0
    subSetTree(arr, cur_arr, num + 1, outputList)

def subSetTree(arr, cur_arr, num, outputList):
    if len(arr) == num :
        outputList.append([val for val in cur_arr if val != None])
        return

    # 选第num个元素
    cur_arr[num] = arr[num]
    subSetTree(arr, cur_arr, num + 1, outputList)

    # 不选第num 个元素,删除第num个元素
    cur_arr[num] = None
    subSetTree(arr, cur_arr, num + 1, outputList)

arr = [1, 2, 3]
cur_arr = range(0,3)
outputList = []
num = 0
subSetTree(arr, cur_arr, num, outputList)
for arr in outputList:
    print arr

 

posted @ 2018-05-04 19:05  ExitQuit  阅读(786)  评论(0编辑  收藏  举报