【问题标题】:How to iterate this tree/graph如何迭代这棵树/图
【发布时间】:2015-04-28 23:50:40
【问题描述】:

我需要迭代树/图并产生一定的输出,但遵循一些规则:

     _ d
   /  / \
  b  c  _e
 /     / |
a     f  g

预期的输出应该是(顺序无关):

{'bde', 'bcde', 'abde', 'abcde', 'bdfe', 'bdfge', 'abdfe', ...}

规则是:

  1. “bde”树的顶部 (leftmost_root_children+root+rightmost_root_children) 应始终存在
  2. 应保留左右顺序,例如不允许使用“cb”或“gf”组合。
  3. 所有路径都遵循从左到右的方向。

我需要找到所有遵循这些规则的路径。不幸的是我没有CS背景,我的脑袋快爆炸了。任何提示都会有所帮助。

编辑:这个结构非常接近地代表了我的树:

class N():
    """Node"""
    def __init__(self, name, lefts, rights):
        self.name = name
        self.lefts = lefts
        self.rights = rights

tree = N('d', [N('b', [N('a', [], [])], []), N('c', [], [])], 
              [N('e', [N('f', [], []), N('g', [], [])], 
                      [])])

或者可能更具可读性:

N('d', lefts =[N('b', lefts=[N('a', [], [])], rights=[]), N('c', [], [])], 
       rights=[N('e', lefts=[N('f', [], []), N('g', [], [])], rights=[])])

【问题讨论】:

  • 展示你的尝试!
  • 说实话我不知道如何开始。我在想一个双循环,但我觉得我需要做一些递归。我就是不能把所有东西放在一起。
  • d 和 f/g 或 b 和 c 之间没有直接路由。很难发现预期输出背后的逻辑(为什么以及何时从 d 跳到 g,然后跳到 f 再回到 e)。
  • 树的开始格式是什么?
  • 你说是二叉树,但是d好像有3个孩子?这个例子是错误的,还是不是二进制的?

标签: python tree


【解决方案1】:

所以这可以被视为两个问题的组合。我下面的代码将假定 N 类和 tree 结构已经在您的问题陈述中定义。

第一:给定一个像你这样的树结构,你如何产生它的节点的有序遍历?这是一个非常简单的问题,所以我将展示一个简单的递归生成器来解决它:

def inorder(node):
    if not isinstance(node, list):
        node = [node]
    for n in node:
        for left in inorder(getattr(n, 'lefts', [])):
            yield left
        yield n.name
        for right in inorder(getattr(n, 'rights', [])):
            yield right

print list(inorder(tree))
# ['a', 'b', 'c', 'd', 'f', 'g', 'e']

第二:现在我们已经有了“正确”的节点顺序,接下来我们需要找出所有可能的组合,a) 保持这个顺序,和 b) 包含三个“锚”元素 ('b', 'd', 'e')。我们可以使用总是方便的itertools 库中的一些帮助来实现这一点。

基本步骤是:

  • 识别锚元素并将列表划分为围绕它们的四部分
  • 找出每个分区的所有元素组合(即功率集)
  • 取所有这些组合的乘积

像这样:

from itertools import chain, combinations
# powerset recipe taken from itertools documentation
def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

def traversals(tree):
    left, mid, right = tree.lefts[0].name, tree.name, tree.rights[0].name
    nodes = list(inorder(tree))
    l_i, m_i, r_i = [nodes.index(x) for x in (left, mid, right)]
    parts = nodes[:l_i], nodes[l_i+1:m_i], nodes[m_i+1:r_i], nodes[r_i+1:]
    psets = [powerset(x) for x in parts]
    for p1, p2, p3, p4 in product(*psets):
        yield ''.join(chain(p1, left, p2, mid, p3, right, p4))

print list(traversals(tree))
# ['bde', 'bdfe', 'bdge', 'bdfge', 'bcde', 'bcdfe', 
#  'bcdge', 'bcdfge', 'abde', 'abdfe', 'abdge', 'abdfge', 
#  'abcde', 'abcdfe', 'abcdge', 'abcdfge']

【讨论】:

  • 很好的答案!现在我知道自己离能够做到这一点还有多远。谢谢!
猜你喜欢
  • 2010-09-24
  • 1970-01-01
  • 2013-09-19
  • 1970-01-01
  • 1970-01-01
  • 2022-11-02
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多