Tìm kiếm một cấu trúc dữ liệu Python Tree tốt [đã đóng]


92

Tôi đang tìm kiếm một lớp cấu trúc dữ liệu Cây tốt. Tôi đã xem qua gói này , nhưng vì tôi còn tương đối mới đối với Python (không phải lập trình), tôi không biết có gói nào tốt hơn ngoài đó không.

Tôi muốn nghe từ Pythonistas ở đây - bạn có tập lệnh cây yêu thích mà bạn thường xuyên sử dụng và muốn giới thiệu không?

[Biên tập]

Để làm rõ, theo 'Cây', ý tôi là một cây đơn giản không có thứ tự (Hmm, đó là một định nghĩa đệ quy một chút - nhưng hy vọng, điều đó làm rõ mọi thứ phần nào). Về những gì tôi cần cây cho (tức là trường hợp sử dụng). Tôi đang đọc dữ liệu cây từ một tệp phẳng và tôi cần xây dựng một cây từ dữ liệu và duyệt qua tất cả các nút trong cây.


Ít nhất một bản sao ba lần ... stackoverflow.com/questions/2482602/… cũng như stackoverflow.com/questions/2358045/…
eric

1
Trong lúc này, có một đơn giản, nhẹ và có thể mở rộng cấu trúc dữ liệu cây: anytree.readthedocs.io/en/latest
c0fec0de

Câu trả lời:


38

Cuộn của riêng bạn. Ví dụ, chỉ cần mô hình cây của bạn dưới dạng danh sách danh sách. Bạn nên nêu chi tiết nhu cầu cụ thể của mình trước khi mọi người có thể đưa ra đề xuất tốt hơn.

Đáp lại câu hỏi của HelloGoodbye, đây là mã mẫu để lặp lại một cây.

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

Một điều đáng chú ý là việc triển khai đệ quy này là O (n log n). Nó hoạt động tốt cho tất cả các cây mà tôi phải đối phó. Có thể trình tạo con trong Python 3 sẽ hữu ích.


Làm thế nào để bạn lặp lại tất cả các yếu tố trong một cái cây như vậy theo một cách 'pythonic'?
HelloGoodbye

Thông thường, bạn lặp lại một cây bằng DFS hoặc BFS. Tôi thường thực hiện một máy phát điện sử dụng DFS như def đi bộ (cây): ...
Wai Yip Tùng

1
DFS và BFS là gì? Những từ viết tắt này là mới đối với tôi.
HelloGoodbye

1
Đã thêm mã mẫu cho DFS.
Wai Yip Tung,

1
Tìm kiếm theo chiều sâu có nghĩa là nút con được truy cập trước các nút anh chị em của nó. vì vậy nếu bạn có `[A, [B, [C, D]], [E, [F, G]]]`, thì giả sử bạn truy cập B trước E, bạn cũng truy cập C và D trước E. Chiều rộng- phương tiện tìm kiếm đầu tiên tất cả các nút cùng cấp đang đến thăm trước khi bất kỳ của con cái họ, vì vậy B và E sẽ cả hai được đến thăm trước khi bất kỳ C, D, F, hoặc G.
Đánh dấu Reed

76

Bạn có thể xây dựng một cây bao gồm các phái đẹp như thế này:

import collections

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

Nó có thể không chính xác những gì bạn muốn nhưng nó khá hữu ích! Giá trị chỉ được lưu trong các nút lá. Đây là một ví dụ về cách nó hoạt động:

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

Để biết thêm thông tin, hãy xem ý chính .


1
Wow, sử dụng defaultdict là một ý tưởng tuyệt vời!
laike9m

Tuyệt vời và tôi tường luôn sử dụng thử ngoại trừ với setters.
Jimmy Kane

5
một nhược điểm là rất khó để thêm các phương thức liên quan đến thao tác trên cây. cũng là trong wiki và gọi autovivification: en.wikipedia.org/wiki/Autovivification#Python
denfromufa

41

Tôi tìm thấy một mô-đun được viết bởi Brett Alistair Kromkamp chưa hoàn thành. Tôi đã hoàn thành nó và công khai nó trên github và đổi tên nó thành treelib(ban đầu pyTree):

https://github.com/caesar0301/treelib

Có thể nó sẽ giúp bạn ....


5
giấy phép GPL là, những gì đáng tiếc
denfromufa

12
Giấy phép này đã được cấp khi tôi thậm chí còn không biết giấy phép có nghĩa là gì. Tôi biết nó là một mô-đun đơn giản nhưng hữu ích. Kể từ phiên bản 1.3.0, tôi phân phối lại nó theo Giấy phép Apache. Bây giờ bạn có thể sử dụng nó ở những nơi bạn cần với tuyên bố về bản quyền gốc.
caesar0301 29/12/14

9

Dựa trên câu trả lời được đưa ra ở trên với Cây một dòng sử dụng defaultdict , bạn có thể biến nó thành một lớp. Điều này sẽ cho phép bạn thiết lập các giá trị mặc định trong một hàm tạo và xây dựng trên nó theo những cách khác.

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

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

Ví dụ này cho phép bạn tạo một tham chiếu ngược để mỗi nút có thể tham chiếu đến cha của nó trong cây.

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

Tiếp theo, bạn thậm chí có thể ghi đè __setattr__ trên Cây lớp để khi gán lại cấp độ gốc, nó sẽ xóa nó như là một phần tử con khỏi cây cấp độ đó. Rất nhiều thứ hay ho với mẫu này.


Parent bị hỏng cho t [0] [1] [2] trong ví dụ trên. AttributeError: Đối tượng 'int' không có thuộc tính 'cha'
MatthieuBizien

@oao Cái này không bị hỏng. Bạn đang chỉ định t [0] [1] [2] = 3. Do đó, t [0] [1] [2] sẽ không phải là loại lệnh mặc định, mà là loại Số (như lệnh mặc định được sử dụng để đặt giá trị mặc định cho phần tử còn thiếu). Nếu bạn muốn nó là một sắc lệnh mặc định, bạn cần sử dụng t [0] [1] [2] mà không cần gán.
Sandy Chapman

7

Đối với một cái cây có những đứa trẻ có thứ tự, tôi thường làm một cái gì đó như thế này (mặc dù ít chung chung hơn một chút, phù hợp với những gì tôi đang làm):

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)

Bạn có thể làm điều gì đó có thể so sánh với a dicthoặc using DictMixinhoặc nó là con cháu hiện đại hơn nếu bạn muốn những đứa trẻ không có thứ tự được truy cập bằng khóa.


7

Nó có thể đáng để viết trình bao bọc cây của riêng bạn dựa trên một đồ thị có hướng xoay vòng bằng cách sử dụng thư viện networkx .


5

Một cách triển khai cây tốt và dễ sử dụng khác trong Python là pyTree: https://github.com/caesar0301/pyTree

pyTree cũng cung cấp khả năng hiển thị hình ảnh cây:

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

2
Một điểm cộng cho việc cố gắng hình dung cây, mặc dù kết xuất rất kinh khủng.
HelloGoodbye


4

Đây là một cái gì đó tôi đang làm việc.

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)

Sử dụng như vậy (các số được sử dụng làm giá trị mẫu): t = Tree(1, Tree(2, Tree(4)), Tree(3, Tree(5)))


3

Would BTrees giúp đỡ? Chúng là một phần của mã Cơ sở dữ liệu đối tượng Zope. Tải xuống toàn bộ gói ZODB là một chút quá mức cần thiết, nhưng tôi hy vọng mô-đun BTrees ít nhất sẽ có thể tách biệt được phần nào.


2

Tôi nghĩ, từ kinh nghiệm của bản thân về các vấn đề với cấu trúc dữ liệu nâng cao hơn, điều quan trọng nhất bạn có thể làm ở đây, là có được kiến ​​thức tốt về khái niệm chung về tress là cấu trúc dữ liệu. Nếu bạn hiểu cơ chế cơ bản đằng sau khái niệm này, sẽ khá dễ dàng để thực hiện giải pháp phù hợp với vấn đề của bạn. Có rất nhiều nguồn tốt trên mạng mô tả khái niệm này. Điều đã "cứu" tôi nhiều năm trước về vấn đề cụ thể này là phần 2.3 trong "Nghệ thuật lập trình máy tính".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.