Найти полный путь элемента в дереве - PullRequest
0 голосов
/ 02 апреля 2019

Я хотел бы найти полный путь элемента в дереве. Элемент может быть расположен в нескольких местах.

дерево

Мой текущий код:

levels = [
    {"L3A": ["L4A"]},
    {"L3B": ["L4B"]},
    {"L3C": ["L4C"]},
    {"L1": ["L2", "L4A"]},
    {"L2": ["L3A", "L3B", "L3C"]}
]

def get_level(name):
    tree = []
    recursive(name, tree)
    return tree

def recursive(name, tree):
    for level in levels:
        for k, v in level.items():
            if name in v:
                tree.append(k)
                recursive(k, tree)

levl = get_level("L4A")
print(levl)

Результат

: ['L3A', 'L2', 'L1', 'L1']

хочу: [['L3A', 'L2', 'L1'], ['L1']]

В конечном итоге хочу:

L4A in L1 > L2 > L3A

L4A in L1 

Не могли бы вы дать мне несколько советов, как это изменить?

Ответы [ 2 ]

0 голосов
/ 02 апреля 2019

Почему L1 появляется дважды в вашем списке?Потому что у вас есть два пути, которые ведут к L4A: L1 -> L2 -> L3A -> L4A и L1 -> L4A, но только одна переменная path для хранения этих путей.Поскольку вы используете вид обратного DFS , у вас есть уровни: L4 -> L3A -> L2 -> L1, затем L4 -> L1.

Давайте попробуем разработать алгоритм.Вы имеете дело с графиком (если вы добавляете корень, вы получаете дерево), поэтому я буду использовать обычный словарь: уровни - это «узлы», а пути между уровнями - это «ребра».Вот хороший способ продолжить:

  • дано: узел N
  • найти все узлы P так, чтобы ребро P-N существовало и сохранить пути.
  • для каждого P найдите все узлы Q, так что ребро P-Q существует, и сохраните пути.
  • , как только не останется edge к узлу Q, то есть текущий path максимален, возвращает path.

Ему не хватает точности, чтобы быть реальным алгоритмом.Давайте сосредоточимся:

GIVEN: a node N
let paths_to_explore = [N]
while paths_to_explore is not empty:
    for every path_to_explore:
        try to add a node at the beginning of path_to_explore
        if it fails, yield path_to_explore

Прежде чем я перейду к коду, обратите внимание, что ваше представление графа не является одним из двух обычных представлений.В вашем случае у вас есть список ребер, но словарь from_node -> [to_nodes] лучше:

edges = {
    "L3A": {"L4A"},
    "L3B": {"L4B"},
    "L3C": {"L4C"},
    "L1": {"L2", "L4A"},
    "L2": {"L3A", "L3B", "L3C"},
}

Это облегчает итерацию по ребрам:

for from_node, to_nodes in edges.items():
    # do something with nodes

Теперь код:

def find_reverse_path(name):
    paths = []
    paths_to_explore = [[name]]
    while paths_to_explore:
        path = paths_to_explore.pop() # next!
        to_node = path[0] # the HEAD of the current path
        expanded = False
        for from_node, to_nodes in edges.items():
            if to_node in to_nodes: # there's an edge to the HEAD
                new_path_to_explore = [from_node] + path # new path = from_node + old path
                paths_to_explore.append(new_path_to_explore) # add it to the exploration list
                expanded = True # this path was expanded

        if not expanded: # the path is maximal
            paths.append(path) # use yield if you want to create a generator

    return paths

print(find_reverse_path("L4A"))

Вывод:

[['L1', 'L4A'], ['L1', 'L2', 'L3A', 'L4A']]

Это итеративная DFS.(Думаю, нам было бы сложнее узнать, был ли путь расширен в рекурсивной DFS.)

Посмотрите на эти две строки, они содержат "трюк":

new_path_to_explore = [from_node] + path # new path = from_node - old path
paths_to_explore.append(new_path_to_explore) # add it to the exploration list

Примечаниечто new_path_to_explore является копией из path, это означает, что мы не просто добавляем узел к paths[-1] (на месте).Это почему?Посмотрите на первые шаги:

1. paths = [[L4A]]
2. paths = [], path = [L4A]
3. append L1-L4A to paths, then append L3A-L4A to paths
4. paths = [[L1, L4A], [L3A, L4A]]
5. paths = [[L1, L4A]], path = [L3A, L4A]
...

Если мы не сделаем копию и если мы найдем несколько ребер в начале текущего пути, мы получим шаг 4 paths = [[L3A, L1, L4]].Это было бы почти той же проблемой, что и у вас в коде.

0 голосов
/ 02 апреля 2019

Переверните ассоциативную карту, затем примените стандартный поиск графа, например. ДФС.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...