Предполагая, что количество желаемых листьев в том же порядке, что и количество листьев, самое простое решение - просто создать общий итератор для всех путей, а затем просто отфильтровать его по совпадениям. Например:
def find_paths(self, targets):
targets = set(targets)
for path in self.iter_all_paths_dfs():
if path[-1].name in targets:
yield path
(или, конечно, вы можете сжать это до одного выражения генератора или filter
вызова, но я написал это явно, чтобы сделать это очевидным.)
И если вы можете сделать это таким образом, вам не нужны обратные указатели или следующие указатели, так что узел может быть точным отображением дочерних имен дочерним узлам, как вы предложили.
Тем не менее, часто проще представить узел как имя и набор дочерних элементов. Для сравнения:
class Node(collections.namedtuple('Node', ('name', 'children'))):
def iter_node_names_dfs(self):
yield self.name
for child in self.children:
yield from child.iter_node_names_dfs()
E = Node('E', ())
F = Node('F', ())
C = Node('C', (E, F))
D = Node('D', ())
Z = Node('Z', (C, D))
X = Node('X', ())
A = Node('A', (X, Z))
tree = A
до:
E = {}
F = {}
C = {'E': {}, 'F': {}}
D = {}
Z = {'C': C, 'D': D}
X = {}
A = {'X': X, 'Z': Z}
tree = {'A': A}
def iter_node_names_dfs(tree):
for name, child in tree.items():
yield name
yield from iter_node_names_dfs(child)
Обратите внимание, что для решения dict требуется дополнительный узел, указывающий на A, чтобы вы могли хранить его имя, а это также означает, что вы не можете получить имя узла от узла; Вы должны запомнить это с предыдущего шага.
Что касается пространства, то здесь не так много различий, но, конечно, вы можете проверить его (повторяя и суммируя sys.getsizeof(node)
, если это вызывает озабоченность).