กำลังมองหาโครงสร้างข้อมูล Python Tree ที่ดี [ปิด]


92

ฉันกำลังมองหาคลาสโครงสร้างข้อมูล Tree ที่ดี ฉันเจอแพ็คเกจนี้แต่เนื่องจากฉันค่อนข้างใหม่กับ Python (ไม่ใช่การเขียนโปรแกรม) ฉันจึงไม่รู้ว่ามีแพ็คเกจที่ดีกว่านี้หรือไม่

ฉันต้องการฟังจาก Pythonistas ที่นี่ - คุณมีสคริปต์ต้นไม้โปรดที่คุณใช้เป็นประจำและจะแนะนำหรือไม่?

[แก้ไข]

เพื่อความชัดเจนโดย 'Tree' ฉันหมายถึงต้นไม้ที่ไม่มีการเรียงลำดับธรรมดา ๆ (อืมนั่นเป็นคำจำกัดความแบบวนซ้ำ - แต่หวังว่าจะให้ความกระจ่างในสิ่งต่างๆบ้าง) เกี่ยวกับสิ่งที่ฉันต้องการต้นไม้ (เช่น use case) ฉันกำลังอ่านข้อมูลทรีจากไฟล์แบบแบนและฉันจำเป็นต้องสร้างต้นไม้จากข้อมูลและสำรวจโหนดทั้งหมดในทรี


อย่างน้อยก็ซ้ำกัน 3 ครั้ง… 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) มันใช้งานได้ดีสำหรับต้นไม้ทั้งหมดที่ฉันต้องจัดการ บางที subgenerator ใน Python 3 อาจช่วยได้


คุณวนซ้ำองค์ประกอบทั้งหมดในต้นไม้ในลักษณะ 'pythonic' ได้อย่างไร?
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 Breadth- การค้นหาครั้งแรกหมายถึงการเยี่ยมชมโหนดทั้งหมดในระดับเดียวกันก่อนลูก ๆ ของพวกเขาดังนั้น B และ E จะถูกเยี่ยมก่อน C, D, F หรือ G ใด ๆ
Mark Reed

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 ยกเว้นกับ setters
Jimmy Kane

5
ข้อเสียอย่างหนึ่งคือการเพิ่มวิธีการที่เกี่ยวข้องกับการปรับแต่งต้นไม้เป็นเรื่องยุ่งยากมาก สิ่งนี้อยู่ใน wiki และเรียกว่า
autovivification

41

ฉันพบโมดูลที่เขียนโดย Brett Alistair Kromkamp ซึ่งยังไม่เสร็จสมบูรณ์ ฉันทำเสร็จแล้วและทำให้เป็นสาธารณะบน github และเปลี่ยนชื่อเป็นtreelib(ดั้งเดิมpyTree):

https://github.com/caesar0301/treelib

มันช่วยคุณได้ ....


5
ใบอนุญาตคือ GPL น่าเสียดาย
denfromufa

12
ใบอนุญาตนี้ได้รับเมื่อฉันไม่รู้ด้วยซ้ำว่าใบอนุญาตหมายถึงอะไร ฉันรู้ว่ามันเป็นโมดูลที่เรียบง่าย แต่มีประโยชน์ ตั้งแต่เวอร์ชัน 1.3.0 ฉันแจกจ่ายใหม่ภายใต้ Apache License ตอนนี้คุณสามารถใช้งานได้ในที่ที่คุณต้องการพร้อมกับประกาศลิขสิทธิ์ดั้งเดิม
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' ไม่มีแอตทริบิวต์ '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หรือเป็นลูกหลานที่ทันสมัยกว่าถ้าคุณต้องการให้เด็กที่ไม่ได้เรียงลำดับเข้าถึงด้วยคีย์



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 การดาวน์โหลดแพ็คเกจ ZODB ทั้งหมดนั้นค่อนข้างเกินความจำเป็น แต่ฉันหวังว่าอย่างน้อยโมดูล BTrees จะแยกออกได้บ้าง


2

ฉันคิดว่าจากประสบการณ์ของฉันเองเกี่ยวกับปัญหาเกี่ยวกับโครงสร้างข้อมูลขั้นสูงสิ่งที่สำคัญที่สุดที่คุณสามารถทำได้ที่นี่คือการได้รับความรู้ที่ดีเกี่ยวกับแนวคิดทั่วไปของปอยเป็นโครงสร้างข้อมูล หากคุณเข้าใจกลไกพื้นฐานที่อยู่เบื้องหลังแนวคิดก็จะเป็นเรื่องง่ายมากที่จะใช้วิธีแก้ปัญหาที่เหมาะกับปัญหาของคุณ มีแหล่งข้อมูลดีๆมากมายที่อธิบายแนวคิดนี้ สิ่งที่ "ช่วย" ฉันไว้เมื่อหลายปีก่อนเกี่ยวกับปัญหานี้คือหัวข้อ 2.3 ใน "ศิลปะการเขียนโปรแกรมคอมพิวเตอร์"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.