如何迭代这个 tree/graph
How to iterate this tree/graph
我需要迭代一个 tree/graph 并产生特定的输出但遵循一些规则:
_ d
/ / \
b c _e
/ / |
a f g
预期的输出应该是(顺序无关):
{'bde', 'bcde', 'abde', 'abcde', 'bdfe', 'bdfge', 'abdfe', ...}
规则是:
- 树的顶端'bde' (leftmost_root_children+root+rightmost_root_children) 应该始终存在
- 应保留左右顺序,因此不允许组合 'cb' 或 'gf'。
- 所有路径都遵循从左到右的方向。
我需要找到遵循这些规则的所有路径。不幸的是,我没有 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=[])])
所以这可以看作是两个问题的组合。我下面的代码将假定 N
class 和 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']
其次: 现在我们有了节点的 "correct" 排序,接下来我们需要找出所有可能的组合 a ) 保持这个顺序,b) 包含三个 "anchor" 元素 ('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']
我需要迭代一个 tree/graph 并产生特定的输出但遵循一些规则:
_ d
/ / \
b c _e
/ / |
a f g
预期的输出应该是(顺序无关):
{'bde', 'bcde', 'abde', 'abcde', 'bdfe', 'bdfge', 'abdfe', ...}
规则是:
- 树的顶端'bde' (leftmost_root_children+root+rightmost_root_children) 应该始终存在
- 应保留左右顺序,因此不允许组合 'cb' 或 'gf'。
- 所有路径都遵循从左到右的方向。
我需要找到遵循这些规则的所有路径。不幸的是,我没有 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=[])])
所以这可以看作是两个问题的组合。我下面的代码将假定 N
class 和 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']
其次: 现在我们有了节点的 "correct" 排序,接下来我们需要找出所有可能的组合 a ) 保持这个顺序,b) 包含三个 "anchor" 元素 ('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']