Шукаємо хорошу структуру даних Python Tree [закрито]


92

Я шукаю хороший клас структури даних дерева. Я натрапив на цей пакет , але оскільки я відносно новачок у Python (не програмує), я не знаю, чи є якісь кращі.

Я хотів би почути від Pythonistas тут - чи є у вас улюблений скрипт дерева, який ви регулярно використовуєте і який би рекомендував?

[Редагувати]

Щоб пояснити, під «Деревом» я маю на увазі просте невпорядковане дерево (Хм, це трохи рекурсивне визначення - але, сподіваюся, це дещо уточнює речі). Щодо того, для чого мені потрібно дерево (тобто випадку використання). Я читаю дані дерева з плоского файлу, і мені потрібно побудувати дерево з даних і пройти всі вузли у дереві.


Принаймні потрійний дублікат ... stackoverflow.com/questions/2482602/… , а також stackoverflow.com/questions/2358045/…
eric

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 (дерево): ...
Wai Yip Tung

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
Ого, використання дефолтного рішення - це чудова ідея!
laike9m

Чудово, і я завжди використовую спробу, за винятком сетерів.
Джиммі Кейн,

5
один мінус - дуже складно додавати методи, пов’язані з маніпуляціями з деревами. також це є у вікі і називається автовівіфікацією: en.wikipedia.org/wiki/Autovivification#Python
denfromufa

41

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

https://github.com/caesar0301/treelib

Нехай це допоможе вам ....


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__ у дереві класів, щоб при перепризначенні батьківського права він видалив його як дочірній з цього батька. Багато крутих речей з цим візерунком.


У наведеному вище прикладі батьківський номер розбитий на t [0] [1] [2]. AttributeError: об'єкт 'int' не має атрибута 'батьківський'
MatthieuBizien

@oao Це не порушено. Ви вказуєте t [0] [1] [2] = 3. Тому t [0] [1] [2] буде не типовим судженням, а типом Числа (оскільки за замовчуванням за замовчуванням використовується відсутні елементи). Якщо ви хочете, щоб це був вирок за замовчуванням, вам потрібно використовувати 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)

Ви можете зробити щось подібне з dictабо, використовуючи DictMixinйого, або це більш сучасні нащадки, якщо ви хочете, щоб непорядковані діти отримували доступ за ключем.


7

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


5

Ще одна хороша та проста у використанні реалізація дерев у Python - це pyTree: https://github.com/caesar0301/pyTree

pyTree також забезпечує можливість візуалізації дерева:

Harry[harry]
|___ Jane[jane]
|    |___ Diane[diane]
|         |___ George[george]
|              |___ Jill[jill]
|         |___ Mary[mary]
|    |___ Mark[mark]
|___ Bill[bill]

2
Плюс для спроби візуалізувати дерево, хоча візуалізація була жахливою.
HelloGoodbye


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. Завантаження всього пакету ZODB трохи надмірне, але я сподіваюся, що модуль BTrees був би хоча б дещо відокремленим.


2

На моєму власному досвіді щодо проблем з більш досконалими структурами даних, я думаю, що найголовніше, що ви можете зробити тут, - це отримати хороші знання щодо загальної концепції тресу як структури даних. Якщо ви зрозумієте основний механізм, що лежить в основі цієї концепції, буде досить легко реалізувати рішення, яке відповідає вашій проблемі. Існує багато хороших джерел, що описують цю концепцію. Що мене "врятувало" багато років тому з цієї конкретної проблеми, це розділ 2.3 "Мистецтво комп'ютерного програмування".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.