İyi bir Python Ağacı veri yapısı aranıyor [kapalı]


92

İyi bir Tree veri yapısı sınıfı arıyorum. Bu pakete rastladım , ancak Python'da nispeten yeni olduğum için (programlama değil), orada daha iyileri olup olmadığını bilmiyorum.

Burada Pythonistalardan haber almak istiyorum - düzenli olarak kullandığınız ve tavsiye edeceğiniz favori bir ağaç komut dosyanız var mı?

[Düzenle]

Açıklığa kavuşturmak için, 'Ağaç' ile basit bir sıralanmamış ağacı kastediyorum (Hmm, bu biraz özyinelemeli bir tanım - ama umarım, bu işleri bir şekilde açıklığa kavuşturur). Ağaca ihtiyacım olan şeyle ilgili olarak (yani kullanım durumu). Ağaç verilerini düz bir dosyadan okuyorum ve verilerden bir ağaç oluşturmam ve ağaçtaki tüm düğümleri geçmem gerekiyor.



1
Bu arada, basit, hafif ve genişletilebilir bir ağaç veri yapısı var: anytree.readthedocs.io/en/latest
c0fec0de

Yanıtlar:


38

Kendininkini yuvarla. Örneğin, ağacınızı liste listesi olarak modelleyin. İnsanların daha iyi bir öneri sunabilmesinden önce, özel ihtiyaçlarınızı detaylandırmalısınız.

HelloGoodbye'nin sorusuna yanıt olarak, bu bir ağacı yinelemek için örnek bir koddur.

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

Bir yakalama, bu yinelemeli gerçeklemenin O (n log n) olmasıdır. Başa çıkmak zorunda olduğum tüm ağaçlar için iyi çalışıyor. Belki Python 3'teki alt üretici yardımcı olabilir.


Böyle bir ağaçtaki tüm elementleri 'pitonik' bir şekilde nasıl döngü yaparsınız?
HelloGoodbye

Genellikle bir ağacı DFS veya BFS kullanarak yinelersiniz. Genellikle def walk (ağaç) gibi DFS kullanan bir jeneratör uygularım: ...
Wai Yip Tung

1
DFS ve BFS nedir? Bu kısaltmalar benim için yeni.
HelloGoodbye

1
DFS için örnek bir kod eklendi.
Wai Yip Tung

1
Önce derinlik araması, bir düğümün çocuklarının kardeşlerinden önce ziyaret edilmesi anlamına gelir. yani “[A, [B, [C, D]], [E, [F, G]]]` varsa, E'den önce B'yi ziyaret ettiğinizi varsayarsak, E'den önce C ve D'yi de ziyaret edersiniz. Genişlik- ilk arama, aynı seviyedeki tüm düğümlerin çocuklarından önce ziyaret edildiği anlamına gelir, bu nedenle B ve E'nin her ikisi de C, D, F veya
Mark Reed

76

Böyle güzel bir dikt ağacı dikebilirsiniz:

import collections

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

Tam olarak istediğiniz şey olmayabilir ama oldukça kullanışlıdır! Değerler yalnızca yaprak düğümlerde kaydedilir. İşte nasıl çalıştığına dair bir örnek:

>>> 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'})}) 

Daha fazla bilgi için özüne bir göz atın .


1
Vay canına, defaultdict kullanmak harika bir fikir!
laike9m

Harika ve ayarlayıcılar dışında her zaman try kullanarak duvarlarım.
Jimmy Kane

5
bir dezavantajı, ağaç manipülasyonları ile ilgili yöntemler eklemenin çok zor olmasıdır. Ayrıca bu wiki olup autovivification seslendi: en.wikipedia.org/wiki/Autovivification#Python
denfromufa

41

Brett Alistair Kromkamp tarafından yazılmış, tamamlanmamış bir modül buldum. Bitirdim ve github'da herkese açık hale getirdim ve treelib(orijinal pyTree) olarak yeniden adlandırdım :

https://github.com/caesar0301/treelib

Size yardımcı olabilir ...


5
lisans GPL, ne yazık
denfromufa

12
Bu ehliyet, ehliyetin ne anlama geldiğini bile bilmediğimde verildi. Bunun basit ama kullanışlı bir modül olduğunu biliyorum. 1.3.0 sürümünden beri, onu Apache Lisansı altında yeniden dağıtıyorum. Şimdi, orijinal telif hakkı beyanıyla ihtiyacınız olan yerde kullanabilirsiniz.
caesar0301

9

Bina defaultdict kullanarak tek bir satır Ağacı ile yukarıda verilen cevap , bunun bir sınıf yapabilirsiniz. Bu, bir yapıcıda varsayılanları ayarlamanıza ve başka şekillerde üzerine inşa etmenize izin verecektir.

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

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

Bu örnek, her düğümün ağaçtaki ebeveynine başvurabilmesi için bir geri referans oluşturmanıza olanak tanır.

>>> 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

Daha sonra, __setattr__ öğesini sınıf Ağacı üzerinde geçersiz kılabilirsiniz, böylece ebeveyni yeniden atarken, onu bu ebeveynden çocuk olarak kaldırır. Bu desenle pek çok harika şey.


Yukarıdaki örnekte t [0] [1] [2] için üst öğe kesilmiştir. AttributeError: 'int' nesnesinin 'ebeveyn' niteliği yok
MatthieuBizien

@oao Bu bozuk değil. T [0] [1] [2] = 3'ü belirtiyorsunuz. Bu nedenle t [0] [1] [2] bir varsayılan dikt türü değil, bir Sayı türü (varsayılan dikte olarak eksik öğeler). Varsayılan bir dikt olmasını istiyorsanız, atama yapmadan t [0] [1] [2] kullanmanız gerekir.
Sandy Chapman

7

Düzenli çocukları olan bir ağaç için, genellikle böyle bir şey yapardım (biraz daha az genel olsa da, yaptığıma göre uyarlanmış):

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)

Sırasız çocuklara anahtarla erişilmesini istiyorsanız , a dictveya kullanarak DictMixinveya daha modern torunları ile karşılaştırılabilir bir şey yapabilirsiniz .


7

Networkx kitaplığını kullanarak döngüsel olmayan yönlendirilmiş bir grafiğe dayalı kendi ağaç sarmalayıcınızı yazmaya değer olabilir .


4

İşte üzerinde çalıştığım bir şey.

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)

Şöyle kullanın (örnek değerler olarak kullanılan sayılar): t = Tree(1, Tree(2, Tree(4)), Tree(3, Tree(5)))


3

Misiniz BTrees bir yardım? Zope Nesne Veritabanı kodunun parçasıdırlar. Tüm ZODB paketini indirmek biraz abartılı, ancak umarım BTrees modülü en azından biraz ayrılabilir olur.


2

Bence, daha gelişmiş veri yapıları ile ilgili problemler konusundaki tecrübelerime göre, burada yapabileceğiniz en önemli şey, veri yapıları olarak ağın genel kavramı hakkında iyi bir bilgi sahibi olmaktır. Kavramın arkasındaki temel mekanizmayı anlarsanız, probleminize uyan çözümü uygulamak oldukça kolay olacaktır. Konsepti açıklayan pek çok iyi kaynak var. Yıllar önce bu problemden beni "kurtaran", "Bilgisayar Programlama Sanatı" nın 2.3 numaralı bölümüydü.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.