Вопрос обхода дерева Python

мне трудно с пересечением деревьев, и поэтому избегайте его, как чумы... обычно.

у меня есть класс, вроде бы (слегка упрощенная версия здесь, но функционально такая же) как:

class Branch(object):
    def __init__(self, title, parent=None):
        self.title = title
        self.parent = parent

у меня есть словарь из кучи Branch экземпляры, названия каждого из них в качестве ключей:

tree = {'Foo Branch': foo, 'Sub-Foo Branch': sub_foo, 'Bar Branch': bar}

теперь я знаю, что существуют сложные алгоритмы для эффективного обхода (например, MPTT, et al), особенно для использования с проекты баз данных, где вопросы эффективности наиболее. Я вообще не использую базу данных, только простые объекты в памяти.

учитывая title of a Branch, мне нужен list всех потомков этой ветви (дети, дети детей, так далее) от tree, так:

  1. вы все равно рекомендовали бы использовать сложный (для моего мозга без Альго :) алгоритм, такой как MPTT для эффективности в моем случае, или есть простой способ достичь это в одной функции?
  2. если да, то какую вы бы порекомендовали, зная, что я не использую базу?
  3. можете ли вы привести пример, или это намного больше, чем я думаю?

Примечание: это не домашнее задание. Я не в школе. Я действительно плохо разбираюсь в алгоритмах. Я использовал Django MPTT для проекта, который требовал деревьев, хранящихся в БД... но все равно не очень хорошо понимаю.

1 ответов


http://en.wikipedia.org/wiki/Depth-first_search

http://en.wikipedia.org/wiki/Tree_traversal

Вы пройти следующим образом в два этапа:

  • первый проход: Поиск узла запроса с соответствующим ключом. (Этот шаг не нужен, если у вас есть hashmap все узлы во всем дереве; у вас есть это (хорошо), поэтому этот шаг не необходимый.)

  • второй проход: вызовите модифицированную версию алгоритма на узле запроса, но на этот раз, когда вы посещаете узел, дайте ему (или добавьте его к нелокальной переменной аккумулятора).

однако ваша ситуация немного странная, потому что обычно деревья имеют указатели на детей, а также, вроде как список с двойной связью. К сожалению, у нас нет такой информации... но, к счастью, легко добавить, что информация:

nodes = tree.values()
for node in nodes:
    if node.parent:
        if not hasattr(node.parent, 'children'):
            node.parent.children = []
        node.parent.children +=[ node ]

теперь мы можем продолжить наш пример:

def traverse(root, callback):
    """
        Peform callback on all nodes in depth-first order
        e.g. traverse(root, lambda x:print(x))
    """
    yield root, callback(root)
    for child in root.children:
        traverse(child)

def getAllDescendents(title):
    queryNode = titlesToNodes[title]  #what you call 'tree'
    for node,blah in traverse(queryNode, lambda x:None):
        yield node