Ищете хорошую структуру данных Python Tree [закрыто]

92

Я ищу хороший класс структуры данных Tree. Я наткнулся на этот пакет , но поскольку я относительно новичок в Python (не в программировании), я не знаю, есть ли какие-нибудь лучшие.

Я хотел бы услышать здесь Pythonistas - есть ли у вас любимый скрипт дерева, который вы регулярно используете и который порекомендовали бы?

[Редактировать]

Чтобы уточнить, под «деревом» я подразумеваю простое неупорядоченное дерево (хм, это немного рекурсивное определение, но, надеюсь, это несколько проясняет ситуацию). Относительно того, для чего мне нужно дерево (например, вариант использования). Я читаю данные дерева из плоского файла, и мне нужно построить дерево из данных и пройти все узлы в дереве.

морфный
источник
По крайней мере, тройной дубликат ... stackoverflow.com/questions/2482602/…, а также stackoverflow.com/questions/2358045/…
Эрик
1
А пока существует простая, легкая и расширяемая древовидная структура данных: anytree.readthedocs.io/en/latest
c0fec0de

Ответы:

38

Сверните свой собственный. Например, просто смоделируйте свое дерево как список списка. Вы должны подробно описать свои конкретные потребности, прежде чем люди смогут дать более точные рекомендации.

В ответ на вопрос HelloGoodbye это пример кода для итерации дерева.

def walk(node):
    """ iterate tree in pre-order depth-first search order """
    yield node
    for child in node.children:
        for n in walk(child):
            yield n

Уловка заключается в том, что эта рекурсивная реализация - O (n log n). Он отлично работает для всех деревьев, с которыми мне приходится иметь дело. Может быть, подгенератор в Python 3 поможет.

Вай Ип Тунг
источник
Как вы перебираете все элементы в таком дереве «питоническим» способом?
HelloGoodbye
Обычно вы перебираете дерево с помощью DFS или BFS. Я обычно реализую генератор с использованием DFS, например def walk (tree): ...
Вай Ип Тунг
1
Что такое DFS и BFS? Эти сокращения для меня новы.
HelloGoodbye
1
Добавлен пример кода для DFS.
Вай Ип Тунг
1
Поиск в глубину означает, что дочерние узлы посещаются раньше его братьев и сестер. поэтому, если у вас есть «[A, [B, [C, D]], [E, [F, G]]]», то, если вы посетите B перед E, вы также посетите C и D перед E. Ширина- Первый поиск означает, что все узлы на одном уровне посещаются раньше любого из их дочерних узлов, поэтому оба узла B и E будут посещены до любого из C, D, F или G.
Марк Рид,
76

Вы можете построить красивое дерево из словосочетаний следующим образом:

import collections

def Tree():
    return collections.defaultdict(Tree)

Возможно, это не совсем то, что вам нужно, но весьма полезно! Значения сохраняются только в листовых узлах. Вот пример того, как это работает:

>>> t = Tree()
>>> t
defaultdict(<function tree at 0x2142f50>, {})
>>> t[1] = "value"
>>> t[2][2] = "another value"
>>> t
defaultdict(<function tree at 0x2142f50>, {1: 'value', 2: defaultdict(<function tree at 0x2142f50>, {2: 'another value'})}) 

Для получения дополнительной информации взгляните на суть .

Стефан
источник
1
Вау, использование defaultdict - отличная идея!
laike9m
Отлично, и я всегда использую try, кроме сеттеров.
Джимми Кейн
5
одним из недостатков является то, что очень сложно добавить методы, связанные с манипуляциями с деревом. также это есть в вики и называется автовивификацией: en.wikipedia.org/wiki/Autovivification#Python
denfromufa
41

Я нашел модуль, написанный Бреттом Алистером Кромкампом, который не был завершен. Я закончил его, выложил на github и переименовал в treelib(оригинал pyTree):

https://github.com/caesar0301/treelib

Может вам помочь ....

caesar0301
источник
5
лицензия GPL, а жаль
denfromufa
12
Эта лицензия была дана, когда я даже не знал, что такое лицензия. Я знаю, что это простой, но полезный модуль. Начиная с версии 1.3.0, я распространяю его под лицензией Apache. Теперь вы можете использовать его там, где вам это нужно, с заявлением об авторских правах.
caesar0301
9

Основываясь на приведенном выше ответе с однострочным деревом с использованием defaultdict , вы можете сделать его классом. Это позволит вам установить значения по умолчанию в конструкторе и использовать его другими способами.

class Tree(defaultdict):
    def __call__(self):
        return Tree(self)

    def __init__(self, parent):
        self.parent = parent
        self.default_factory = self

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

>>> t = Tree(None)
>>> t[0][1][2] = 3
>>> t
defaultdict(defaultdict(..., {...}), {0: defaultdict(defaultdict(..., {...}), {1: defaultdict(defaultdict(..., {...}), {2: 3})})})
>>> t[0][1].parent
defaultdict(defaultdict(..., {...}), {1: defaultdict(defaultdict(..., {...}), {2: 3})})
>>> t2 = t[0][1]
>>> t2
defaultdict(defaultdict(..., {...}), {2: 3})
>>> t2[2]
3

Затем вы даже можете переопределить __setattr__ в классе Tree, чтобы при переназначении родителя он удалял его как дочерний элемент этого родителя. Много крутых вещей с этим рисунком.

Сэнди Чепмен
источник
В приведенном выше примере родительский элемент нарушен для t [0] [1] [2]. AttributeError: объект int не имеет атрибута parent
MatthieuBizien
@oao Это не сломано. Вы указываете t [0] [1] [2] = 3. Поэтому t [0] [1] [2] будет не типом defaultdict, а типом Number (поскольку defaultdict используется для установки значений по умолчанию для недостающие элементы). Если вы хотите, чтобы он был дефолтным, вам нужно использовать t [0] [1] [2] без присваивания.
Sandy Chapman
7

Для дерева с упорядоченными дочерними элементами я обычно делаю что-то вроде этого (хотя и немного менее общего, с учетом того, что я делаю):

class TreeNode(list):

    def __init__(self, iterable=(), **attributes):
        self.attr = attributes
        list.__init__(self, iterable)

    def __repr__(self):
        return '%s(%s, %r)' % (type(self).__name__, list.__repr__(self),
            self.attr)

Вы можете сделать что-то сопоставимое с a dictили с помощью DictMixinили с его более современными потомками, если хотите, чтобы неупорядоченные дочерние элементы были доступны по ключу.

Мэтт Андерсон
источник
7

Возможно, стоит написать собственную оболочку дерева на основе ациклического ориентированного графа с использованием библиотеки networkx .

Эндрю Уокер
источник
4

Вот над чем я работал.

class Tree:
    def __init__(self, value, *children):
        '''Singly linked tree, children do not know who their parent is.
        '''
        self.value = value
        self.children = tuple(children)

    @property
    def arguments(self):
        return (self.value,) + self.children

    def __eq__(self, tree):
        return self.arguments == tree.arguments

    def __repr__(self):
        argumentStr = ', '.join(map(repr, self.arguments))
        return '%s(%s)' % (self.__class__.__name__, argumentStr)

Используйте как таковые (числа используются в качестве примеров значений): t = Tree(1, Tree(2, Tree(4)), Tree(3, Tree(5)))

Аарон Робсон
источник
3

Поможет ли BTrees ? Они являются частью кода Zope Object Database. Загрузка всего пакета ZODB - это немного излишне, но я надеюсь, что модуль BTrees будет хотя бы в некоторой степени отделимым.

Дженн Д.
источник
2

Я думаю, исходя из моего собственного опыта решения проблем с более продвинутыми структурами данных, самое важное, что вы можете здесь сделать, - это получить хорошее представление об общей концепции прядей как структур данных. Если вы поймете основной механизм, лежащий в основе концепции, будет довольно легко реализовать решение, соответствующее вашей проблеме. Есть много хороших источников, описывающих эту концепцию. Много лет назад меня «спас» от этой конкретной проблемы раздел 2.3 в «Искусстве компьютерного программирования».

У. Хьорт
источник