Estou tentando encontrar um algoritmo de tree walker "poderoso/versátil" não recursivo, que, em última análise, produza não apenas o nó, mas a profundidade do nó, seu índice pai e irmão, e seja capaz de usar uma busca em largura (BFS) ou busca em profundidade (DFS).
É possível combinar depth-first e bread-first assim, apenas produzindo o nó (NB assume um nó que pode ou não ter a chave CHILD_NODES
). Exemplo usando Python - tag "Python" adicionada, mas obviamente não específica:
def get_walker(walk_by_depth=True):
def walk(root):
queue = [root]
while len(queue) > 0:
# the first item in the queue
node_to_yield = queue.pop(0)
yield node_to_yield
if CHILD_NODES in node_to_yield:
depth += 1
new_nodes = node_to_yield[CHILD_NODES]
if walk_by_depth:
queue = new_nodes + queue
else:
queue.extend(new_nodes)
return walk
... e adicionar uma pequena quantidade de código permite que você obtenha uma profundidade somente para uma busca em largura :
def get_walker(walk_by_depth=True):
def walk(root):
queue = [root]
depth = 0
depth_map_of_remaining_items = {0: 1}
while len(queue) > 0:
node_to_yield = queue.pop(0)
if depth_map_of_remaining_items[depth] == 0:
depth += 1
depth_map_of_remaining_items[depth] -= 1
yield node_to_yield, depth
if CHILD_NODES in node_to_yield:
depth += 1
new_nodes = node_to_yield[CHILD_NODES]
if walk_by_depth:
queue = new_nodes + queue
else:
queue.extend(new_nodes)
if depth not in depth_map_of_remaining_items:
depth_map_of_remaining_items[depth] = 0
depth_map_of_remaining_items[depth] += len(new_nodes)
depth -= 1
return walk
O código acima não funciona de fato com walk_by_depth=True
: ele não levanta uma Exception, ele apenas erra a profundidade. Instintivamente, tenho a sensação de que o código provavelmente só precisa de um ajuste mínimo para renderizar (corrigir) depth
em um DFS, mas não tive sucesso até agora.
A questão é que, se eu puder encontrar uma maneira de produzir a profundidade com um DFS, acredito que será um passo bem fácil produzir, tanto para BFS quanto para DFS, o nó pai, mantendo um mapa "profundidade-para-último-nó". Se você puder obter o pai, também poderá obter o índice irmão, no máximo usando o método list
de index
(embora possa haver maneiras muito mais inteligentes de obter o índice pai e irmão...).
A ideia é colocar a profundidade na fila também: coloque pares de nós com suas profundidades na fila, e será fácil.
Sem alterar mais do que o necessário no seu código para fazê-lo funcionar, obtemos isto:
Note que
pop(0)
enew_nodes + queue
não são operações eficientes. Considere usar um deque.Implementação usando
deque
conforme sugerido por trincot, produzindo nó, profundidade, índice pai e irmão: