Чтобы выполнить поиск в ширину , мы должны хранить список текущих рабочих узлов и деревьев под ними - я решил сохранить их в кортеже.
Например, когда мы работаем на глубине узлов c
и d
, этот список деревьев будет:
[('c': {'x': {}}), ('d': {'p': {}})]
Теперь , в то время как под нами все еще есть деревья (while len(trees):
), нам нужно спуститься к слою ниже в нашем дереве.
Первый шаг, очевидно, состоит в том, чтобы сбросить список trees
, так как мы будем генерировать следующий слой.
Затем мы перебираем наш список деревьев и для каждого дерева мы перебираем его дочерние элементы.
Итак, в приведенном выше примере на первой итерации узел будет 'c'
, а дочерние элементы будут: {'x': {}}
, и теперь мы хотим перебрать дочерние элементы. Таким образом, на первой итерации этого дочернего цикла первый дочерний узел будет 'x'
, а его дочерние элементы (дочерние элементы c
) будут пустыми: {}
.
Теперь, в этой области (дочернем узле), если у дочернего элемента есть дочерние элементы, мы хотим добавить дочерний элемент и его дочерние элементы (опять же, как кортеж) в список деревьев.
Так, чтобы привести пример, где есть дочерние элементы, когда текущий узел равен b
, то один из его дочерних элементов равен c
, а поскольку у c
есть дочерние элементы, кортеж (c
, * 1033) * 's children) добавляется в список деревьев для следующего слоя.
Наконец, независимо от того, были ли у этого ребенка дети или нет, мы хотим, чтобы в текущей строке файла была связь между нами и ними. Это (node, child_node)
.
И это почти все. Конечно, когда мы заканчиваем целое дерево, нам нужно записать новую строку в файл.
Единственная досадная деталь - проблема пробелов между кортежами, записанными в файл. Если бы мы всегда объединяли пробел в конце каждого кортежа, в конце каждой строки мы могли бы получить паразитный пробел, как показано ниже, что не идеально.
(ROOT, a)S(a,b)S
(где S
представляет пробел)
Таким образом, чтобы выкупить это, мы всегда будем объединять пробел перед каждым кортежем, пока мы не первые в новой строке (line_first
). Чтобы это работало, в начале каждого дерева (строки) мы устанавливаем флаг line_first
на True
, но затем в коде мы сразу устанавливаем его на False
на первой итерации (но пропускаем запись пробел), иначе (будущие кортежи) мы пишем пробел раньше.
И это все. Вот полный код:
the_tree = {'a': {'b': {'c': {'x': {}}, 'd': {'p': {}}}, 'g': {}, 'f': {}},
't': {'r': {'o': {}}, 'y': {}}}
with open('the_file', 'w') as file:
for tree in the_tree.values():
line_first = True
trees = [('ROOT', tree)]
while len(trees):
new_trees = []
for node, children in trees:
for child_node, child_children in children.items():
if child_children:
new_trees.append((child_node, child_children))
if line_first: line_first = False
else: file.write(' ')
file.write(f'({node}, {child_node})')
trees = new_trees
file.write('\n')
предупреждение: использует f-strings
, которые были введены в версии 3.6!
И выдает намеченный результат:
(ROOT, b) (ROOT, g) (ROOT, f) (b, c) (b, d) (c, x) (d, p)
(ROOT, r) (ROOT, y) (r, o)