ฉันจะติดตั้งแผนผังใน Python ได้อย่างไร?


204

ฉันกำลังพยายามสร้างต้นไม้ทั่วไป

มีโครงสร้างข้อมูลใด ๆ ใน Python ที่จะใช้หรือไม่


5
laurentluce.com/posts/binary-search-tree-library-in-python คำอธิบายที่ดี ....
GrvTyagi

@GrvTyagi ลิงก์ไม่ทำงาน
โทนี่ลูคัส

คำตอบ:


232

anytree

ฉันแนะนำhttps://pypi.python.org/pypi/anytree (ฉันเป็นผู้เขียน)

ตัวอย่าง

from anytree import Node, RenderTree

udo = Node("Udo")
marc = Node("Marc", parent=udo)
lian = Node("Lian", parent=marc)
dan = Node("Dan", parent=udo)
jet = Node("Jet", parent=dan)
jan = Node("Jan", parent=dan)
joe = Node("Joe", parent=dan)

print(udo)
Node('/Udo')
print(joe)
Node('/Udo/Dan/Joe')

for pre, fill, node in RenderTree(udo):
    print("%s%s" % (pre, node.name))
Udo
├── Marc
   └── Lian
└── Dan
    ├── Jet
    ├── Jan
    └── Joe

print(dan.children)
(Node('/Udo/Dan/Jet'), Node('/Udo/Dan/Jan'), Node('/Udo/Dan/Joe'))

คุณสมบัติ

anytreeยังมี API ที่ทรงพลังด้วย:

  • การสร้างต้นไม้อย่างง่าย
  • การปรับเปลี่ยนต้นไม้อย่างง่าย
  • สั่งซื้อซ้ำต้นไม้
  • การทรีทรีแบบต้นไม้สั่งซื้อล่วงหน้า
  • แก้ไขพา ธ ของโหนดแบบสัมพันธ์และแบบสัมบูรณ์
  • เดินจากโหนดหนึ่งไปอีกโหนดหนึ่ง
  • การแสดงผลต้นไม้ (ดูตัวอย่างด้านบน)
  • โหนดแนบ / แยก hookups

31
คำตอบที่ดีที่สุดก็คือ
Ondrej

66
เป็นแบบฟอร์มที่ดีที่จะเปิดเผยว่าคุณเป็นผู้แต่งแพ็คเกจที่คุณแนะนำในคำตอบของคุณ
John Y

3
@ c0fec0de ฉันรักคุณ !!!! ห้องสมุดนี้น่าทึ่งแม้มีฟังก์ชั่นการสร้างภาพ
layser

2
@ ตอบคำถามได้ดีคำตอบอื่น ๆ คือการพึ่งพาน้อยลงและคำถามเดิมถามเกี่ยวกับโครงสร้างข้อมูลในตัว ในขณะที่anytreeอาจเป็นห้องสมุดที่ยอดเยี่ยมนี่เป็นคำถามงูหลามไม่ใช่คำถามของ Node.js
Rob Rose

ฉันเจอคำตอบนี้ผ่านทาง Google ห้องสมุดนี้ดีจริงๆ ฉันชอบความสามารถในการใช้คลาส mixin เพื่อสร้างต้นไม้ของวัตถุใด ๆ !
R Nck Nöthing

104

Python ไม่มีโครงสร้างข้อมูลที่หลากหลาย "ค่อนข้างมีอยู่ภายใน" เช่นเดียวกับ Java อย่างไรก็ตามเนื่องจาก Python นั้นเป็นแบบไดนามิกทรีทั่วไปจึงสร้างได้ง่าย ตัวอย่างเช่นต้นไม้ไบนารีอาจเป็น:

class Tree:
    def __init__(self):
        self.left = None
        self.right = None
        self.data = None

คุณสามารถใช้สิ่งนี้:

root = Tree()
root.data = "root"
root.left = Tree()
root.left.data = "left"
root.right = Tree()
root.right.data = "right"

109
สิ่งนี้ไม่ได้อธิบายมากนักเกี่ยวกับการทำให้ต้นไม้มีประโยชน์
Mike Graham

14
คำถามถูกติดแท็กด้วย Python3, ไม่จำเป็นต้องได้รับมาclass Treeจากอ็อบเจกต์
cfi

3
@cfi มาจากobjectบางครั้งก็เป็นแนวทาง:ถ้าชั้นเรียนสืบทอดจากไม่มีฐานชั้นอื่น ๆ อย่างชัดเจนสืบทอดมาจากวัตถุ นอกจากนี้ยังใช้กับคลาสที่ซ้อนกัน ดูคู่มือสไตล์ Google Python
Konrad Reiche

16
@platzhirsch: โปรดอ่านและอ้างแนวทางอย่างสมบูรณ์: Google ชี้ให้เห็นอย่างชัดเจนว่านี่เป็นสิ่งจำเป็นสำหรับรหัส Python 2 ในการทำงานตามที่คาดไว้และแนะนำให้ปรับปรุงความเข้ากันได้กับ Py3 ที่นี่เรากำลังพูดถึงรหัส Py3 ไม่จำเป็นต้องพิมพ์แบบพิเศษเพิ่มเติม
cfi

13
นั่นเป็นต้นไม้ไบนารีไม่ใช่ต้นไม้ทั่วไปที่ถูกถาม
Michael Dorner

49

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

ไม่มีโครงสร้างข้อมูลแบบบิวอินสำหรับต้นไม้ทั่วไปใน Python แต่ถูกนำไปใช้กับคลาสได้อย่างง่ายดาย

class Tree(object):
    "Generic tree node."
    def __init__(self, name='root', children=None):
        self.name = name
        self.children = []
        if children is not None:
            for child in children:
                self.add_child(child)
    def __repr__(self):
        return self.name
    def add_child(self, node):
        assert isinstance(node, Tree)
        self.children.append(node)
#    *
#   /|\
#  1 2 +
#     / \
#    3   4
t = Tree('*', [Tree('1'),
               Tree('2'),
               Tree('+', [Tree('3'),
                          Tree('4')])])

น่าทึ่งนี่สามารถใช้เป็นกราฟได้อย่างง่ายดายเช่นกัน! ปัญหาเดียวที่ฉันเห็นคือ: ฉันจะแตกต่างโหนดซ้ายจากโหนดขวาได้อย่างไร
Ângelo Polotto

3
โดยดัชนีลูก สิ่งที่เหลือจะเป็นลูก [0] ในกรณีนั้นเสมอ
Freund Allein

38

คุณสามารถลอง:

from collections import defaultdict
def tree(): return defaultdict(tree)
users = tree()
users['harold']['username'] = 'hrldcpr'
users['handler']['username'] = 'matthandlersux'

ตามที่แนะนำไว้ที่นี่: https://gist.github.com/2012250


หากคุณต้องการขยายเป็นระดับการตรวจสอบโดยพลการ: stackoverflow.com/a/43237270/511809
natbusa

เงานี้สร้างฟังก์ชันแฮชในตัว
Tritium21

20
class Node:
    """
    Class Node
    """
    def __init__(self, value):
        self.left = None
        self.data = value
        self.right = None

class Tree:
    """
    Class tree will provide a tree as well as utility functions.
    """

    def createNode(self, data):
        """
        Utility function to create a node.
        """
        return Node(data)

    def insert(self, node , data):
        """
        Insert function will insert a node into tree.
        Duplicate keys are not allowed.
        """
        #if tree is empty , return a root node
        if node is None:
            return self.createNode(data)
        # if data is smaller than parent , insert it into left side
        if data < node.data:
            node.left = self.insert(node.left, data)
        elif data > node.data:
            node.right = self.insert(node.right, data)

        return node


    def search(self, node, data):
        """
        Search function will search a node into tree.
        """
        # if root is None or root is the search data.
        if node is None or node.data == data:
            return node

        if node.data < data:
            return self.search(node.right, data)
        else:
            return self.search(node.left, data)



    def deleteNode(self,node,data):
        """
        Delete function will delete a node into tree.
        Not complete , may need some more scenarion that we can handle
        Now it is handling only leaf.
        """

        # Check if tree is empty.
        if node is None:
            return None

        # searching key into BST.
        if data < node.data:
            node.left = self.deleteNode(node.left, data)
        elif data > node.data:
            node.right = self.deleteNode(node.right, data)
        else: # reach to the node that need to delete from BST.
            if node.left is None and node.right is None:
                del node
            if node.left == None:
                temp = node.right
                del node
                return  temp
            elif node.right == None:
                temp = node.left
                del node
                return temp

        return node






    def traverseInorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            self.traverseInorder(root.left)
            print root.data
            self.traverseInorder(root.right)

    def traversePreorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            print root.data
            self.traversePreorder(root.left)
            self.traversePreorder(root.right)

    def traversePostorder(self, root):
        """
        traverse function will print all the node in the tree.
        """
        if root is not None:
            self.traversePostorder(root.left)
            self.traversePostorder(root.right)
            print root.data


def main():
    root = None
    tree = Tree()
    root = tree.insert(root, 10)
    print root
    tree.insert(root, 20)
    tree.insert(root, 30)
    tree.insert(root, 40)
    tree.insert(root, 70)
    tree.insert(root, 60)
    tree.insert(root, 80)

    print "Traverse Inorder"
    tree.traverseInorder(root)

    print "Traverse Preorder"
    tree.traversePreorder(root)

    print "Traverse Postorder"
    tree.traversePostorder(root)


if __name__ == "__main__":
    main()

3
คุณสามารถเพิ่มโน้ตเพื่อแนะนำรหัสและการนำไปใช้ของคุณได้ไหม
Michele d'Amico

ขอบคุณสำหรับการใช้งาน Binary Tree ที่สมบูรณ์พร้อมฟังก์ชั่นยูทิลิตี้ เนื่องจากเป็น Python 2 ฉันสร้างส่วนสำคัญสำหรับการนำBinary Tree (Py3) มาใช้สำหรับผู้ที่ต้องการใช้งาน Python 3
CᴴᴀZ

16

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

นอกจากนี้ยังมีการใช้งานมากมายในPyPiที่คุณสามารถเรียกดูได้

ถ้าฉันจำได้ถูกต้อง lib มาตรฐาน Python จะไม่รวมโครงสร้างข้อมูลทรีด้วยเหตุผลเดียวกับที่ไลบรารีคลาสฐาน. NET ไม่: ลดตำแหน่งของหน่วยความจำทำให้สูญเสียแคชมากขึ้น ในตัวประมวลผลที่ทันสมัยมักจะเร็วกว่าเพียงแค่นำหน่วยความจำขนาดใหญ่มาใส่ในแคชและโครงสร้างข้อมูล "ตัวชี้ที่หลากหลาย" ปฏิเสธประโยชน์


2
FYI: interwebs ถูกฉาบด้วยความเกลียดชังกับ Boost เห็นได้ชัดว่ามันควรจะเป็นความเจ็บปวดขนาดใหญ่ที่จะจัดการกับโดยเฉพาะอย่างยิ่งเมื่อได้รับการสนับสนุนมันถูกยกเลิก ดังนั้นฉันขอแนะนำให้อยู่ห่างจากสิ่งนั้น
inspectorG4dget

ขอบคุณ ฉันไม่ได้มีปัญหาใด ๆ เป็นการส่วนตัว แต่ฉันไม่ต้องการที่จะเข้าใจผิดดังนั้นฉันจึงลบการอ้างอิงนั้นออก
Justin R.

11

{child:parent}ผมนำมาใช้เป็นต้นไม้ที่หยั่งรากลึกเป็นพจนานุกรม ตัวอย่างเช่นด้วยโหนดรู0ทต้นไม้อาจมีลักษณะเช่นนั้น:

tree={1:0, 2:0, 3:1, 4:2, 5:3}

โครงสร้างนี้ทำให้มันง่ายขึ้นไปตามเส้นทางจากโหนดไปยังรูตซึ่งเกี่ยวข้องกับปัญหาที่ฉันทำงานอยู่


1
นี่คือวิธีที่ฉันพิจารณาที่จะทำจนกระทั่งฉันเห็นคำตอบ {parent:[leftchild,rightchild]}แม้ว่าตั้งแต่ต้นคือพ่อแม่กับลูกสองคนและถ้าคุณต้องการที่จะไปลงที่คุณสามารถทำได้
JFA

1
อีกวิธีหนึ่งคือการใช้รายการของรายการที่องค์ประกอบแรก (หรือมากกว่า) ในรายการคือค่าโหนดและรายการที่ซ้อนกันสองรายการต่อไปนี้แสดงถึง subtrees ซ้ายและขวา (หรือมากกว่าสำหรับต้นไม้ n-ary)
pepr

9

คำตอบของ Greg Hewgill นั้นยอดเยี่ยม แต่ถ้าคุณต้องการโหนดเพิ่มเติมต่อระดับคุณสามารถใช้ list | dictionary เพื่อสร้าง: จากนั้นใช้เมธอดในการเข้าถึงทั้งชื่อหรือลำดับ (เช่น id)

class node(object):
    def __init__(self):
        self.name=None
        self.node=[]
        self.otherInfo = None
        self.prev=None
    def nex(self,child):
        "Gets a node by number"
        return self.node[child]
    def prev(self):
        return self.prev
    def goto(self,data):
        "Gets the node by name"
        for child in range(0,len(self.node)):
            if(self.node[child].name==data):
                return self.node[child]
    def add(self):
        node1=node()
        self.node.append(node1)
        node1.prev=self
        return node1

ตอนนี้เพียงแค่สร้างรูทและสร้าง: ex:

tree=node()  #create a node
tree.name="root" #name it root
tree.otherInfo="blue" #or what ever 
tree=tree.add() #add a node to the root
tree.name="node1" #name it

    root
   /
child1

tree=tree.add()
tree.name="grandchild1"

       root
      /
   child1
   /
grandchild1

tree=tree.prev()
tree=tree.add()
tree.name="gchild2"

          root
           /
        child1
        /    \
grandchild1 gchild2

tree=tree.prev()
tree=tree.prev()
tree=tree.add()
tree=tree.name="child2"

              root
             /   \
        child1  child2
       /     \
grandchild1 gchild2


tree=tree.prev()
tree=tree.goto("child1") or tree=tree.nex(0)
tree.name="changed"

              root
              /   \
         changed   child2
        /      \
  grandchild1  gchild2

นั่นควรจะเพียงพอสำหรับคุณที่จะเริ่มหาวิธีการทำงานนี้


มีบางอย่างขาดหายไปในคำตอบนี้ฉันลองใช้วิธีแก้ปัญหานี้ในช่วง 2 วันที่ผ่านมาและฉันคิดว่าคุณมีวิธีการเพิ่มตรรกะในการเพิ่มวัตถุ ฉันจะส่งคำตอบสำหรับคำถามนี้โปรดตรวจสอบและแจ้งให้เราทราบหากฉันสามารถช่วยได้
MAULIK MODI

8
class Tree(dict):
    """A tree implementation using python's autovivification feature."""
    def __missing__(self, key):
        value = self[key] = type(self)()
        return value

    #cast a (nested) dict to a (nested) Tree class
    def __init__(self, data={}):
        for k, data in data.items():
            if isinstance(data, dict):
                self[k] = type(self)(data)
            else:
                self[k] = data

ทำงานเป็นพจนานุกรม แต่ให้ dicts ซ้อนกันมากเท่าที่คุณต้องการ ลองทำสิ่งต่อไปนี้:

your_tree = Tree()

your_tree['a']['1']['x']  = '@'
your_tree['a']['1']['y']  = '#'
your_tree['a']['2']['x']  = '$'
your_tree['a']['3']       = '%'
your_tree['b']            = '*'

จะส่งมอบ dict ซ้อนกัน ... ซึ่งทำงานเป็นต้นไม้แน่นอน

{'a': {'1': {'x': '@', 'y': '#'}, '2': {'x': '$'}, '3': '%'}, 'b': '*'}

... หากคุณมี พ.ร.บ. อยู่แล้วมันจะเหวี่ยงแต่ละระดับไปที่ต้นไม้:

d = {'foo': {'amy': {'what': 'runs'} } }
tree = Tree(d)

print(d['foo']['amy']['what']) # returns 'runs'
d['foo']['amy']['when'] = 'now' # add new branch

ด้วยวิธีนี้คุณสามารถแก้ไข / เพิ่ม / ลบแต่ละระดับ dict ตามที่คุณต้องการ วิธี dict ทั้งหมดสำหรับการสำรวจเส้นทาง ฯลฯ ยังคงใช้


2
มีเหตุผลที่คุณเลือกที่จะขยายdictแทนdefaultdictหรือไม่? จากการทดสอบของฉันการขยายdefaultdictแทนการเขียนตามคำบอกจากนั้นเพิ่มself.default_factory = type(self)ไปด้านบนของ init ควรทำงานในลักษณะเดียวกัน
Rob Rose

ฉันอาจจะพลาดบางสิ่งที่นี่คุณจะสำรวจโครงสร้างนี้ได้อย่างไร ดูเหมือนว่าเป็นเรื่องยากมากที่จะไปจากเด็กไปหาพ่อแม่หรือพี่น้อง
Stormsson

6

ฉันใช้ต้นไม้โดยใช้ dicts ที่ซ้อนกัน มันค่อนข้างง่ายที่จะทำและมันได้ผลกับฉันด้วยชุดข้อมูลขนาดใหญ่ ฉันโพสต์ตัวอย่างด้านล่างและคุณสามารถดูเพิ่มเติมได้ที่รหัส Google

  def addBallotToTree(self, tree, ballotIndex, ballot=""):
    """Add one ballot to the tree.

    The root of the tree is a dictionary that has as keys the indicies of all 
    continuing and winning candidates.  For each candidate, the value is also
    a dictionary, and the keys of that dictionary include "n" and "bi".
    tree[c]["n"] is the number of ballots that rank candidate c first.
    tree[c]["bi"] is a list of ballot indices where the ballots rank c first.

    If candidate c is a winning candidate, then that portion of the tree is
    expanded to indicate the breakdown of the subsequently ranked candidates.
    In this situation, additional keys are added to the tree[c] dictionary
    corresponding to subsequently ranked candidates.
    tree[c]["n"] is the number of ballots that rank candidate c first.
    tree[c]["bi"] is a list of ballot indices where the ballots rank c first.
    tree[c][d]["n"] is the number of ballots that rank c first and d second.
    tree[c][d]["bi"] is a list of the corresponding ballot indices.

    Where the second ranked candidates is also a winner, then the tree is 
    expanded to the next level.  

    Losing candidates are ignored and treated as if they do not appear on the 
    ballots.  For example, tree[c][d]["n"] is the total number of ballots
    where candidate c is the first non-losing candidate, c is a winner, and
    d is the next non-losing candidate.  This will include the following
    ballots, where x represents a losing candidate:
    [c d]
    [x c d]
    [c x d]
    [x c x x d]

    During the count, the tree is dynamically updated as candidates change
    their status.  The parameter "tree" to this method may be the root of the
    tree or may be a sub-tree.
    """

    if ballot == "":
      # Add the complete ballot to the tree
      weight, ballot = self.b.getWeightedBallot(ballotIndex)
    else:
      # When ballot is not "", we are adding a truncated ballot to the tree,
      # because a higher-ranked candidate is a winner.
      weight = self.b.getWeight(ballotIndex)

    # Get the top choice among candidates still in the running
    # Note that we can't use Ballots.getTopChoiceFromWeightedBallot since
    # we are looking for the top choice over a truncated ballot.
    for c in ballot:
      if c in self.continuing | self.winners:
        break # c is the top choice so stop
    else:
      c = None # no candidates left on this ballot

    if c is None:
      # This will happen if the ballot contains only winning and losing
      # candidates.  The ballot index will not need to be transferred
      # again so it can be thrown away.
      return

    # Create space if necessary.
    if not tree.has_key(c):
      tree[c] = {}
      tree[c]["n"] = 0
      tree[c]["bi"] = []

    tree[c]["n"] += weight

    if c in self.winners:
      # Because candidate is a winner, a portion of the ballot goes to
      # the next candidate.  Pass on a truncated ballot so that the same
      # candidate doesn't get counted twice.
      i = ballot.index(c)
      ballot2 = ballot[i+1:]
      self.addBallotToTree(tree[c], ballotIndex, ballot2)
    else:
      # Candidate is in continuing so we stop here.
      tree[c]["bi"].append(ballotIndex)

5

ฉันเผยแพร่ Python [3] การใช้งานทรีในเว็บไซต์ของฉัน: http://www.quesucede.com/page/show/id/python_3_tree_implementation

หวังว่ามันจะใช้

ตกลงนี่คือรหัส:

import uuid

def sanitize_id(id):
    return id.strip().replace(" ", "")

(_ADD, _DELETE, _INSERT) = range(3)
(_ROOT, _DEPTH, _WIDTH) = range(3)

class Node:

    def __init__(self, name, identifier=None, expanded=True):
        self.__identifier = (str(uuid.uuid1()) if identifier is None else
                sanitize_id(str(identifier)))
        self.name = name
        self.expanded = expanded
        self.__bpointer = None
        self.__fpointer = []

    @property
    def identifier(self):
        return self.__identifier

    @property
    def bpointer(self):
        return self.__bpointer

    @bpointer.setter
    def bpointer(self, value):
        if value is not None:
            self.__bpointer = sanitize_id(value)

    @property
    def fpointer(self):
        return self.__fpointer

    def update_fpointer(self, identifier, mode=_ADD):
        if mode is _ADD:
            self.__fpointer.append(sanitize_id(identifier))
        elif mode is _DELETE:
            self.__fpointer.remove(sanitize_id(identifier))
        elif mode is _INSERT:
            self.__fpointer = [sanitize_id(identifier)]

class Tree:

    def __init__(self):
        self.nodes = []

    def get_index(self, position):
        for index, node in enumerate(self.nodes):
            if node.identifier == position:
                break
        return index

    def create_node(self, name, identifier=None, parent=None):

        node = Node(name, identifier)
        self.nodes.append(node)
        self.__update_fpointer(parent, node.identifier, _ADD)
        node.bpointer = parent
        return node

    def show(self, position, level=_ROOT):
        queue = self[position].fpointer
        if level == _ROOT:
            print("{0} [{1}]".format(self[position].name,
                                     self[position].identifier))
        else:
            print("\t"*level, "{0} [{1}]".format(self[position].name,
                                                 self[position].identifier))
        if self[position].expanded:
            level += 1
            for element in queue:
                self.show(element, level)  # recursive call

    def expand_tree(self, position, mode=_DEPTH):
        # Python generator. Loosly based on an algorithm from 'Essential LISP' by
        # John R. Anderson, Albert T. Corbett, and Brian J. Reiser, page 239-241
        yield position
        queue = self[position].fpointer
        while queue:
            yield queue[0]
            expansion = self[queue[0]].fpointer
            if mode is _DEPTH:
                queue = expansion + queue[1:]  # depth-first
            elif mode is _WIDTH:
                queue = queue[1:] + expansion  # width-first

    def is_branch(self, position):
        return self[position].fpointer

    def __update_fpointer(self, position, identifier, mode):
        if position is None:
            return
        else:
            self[position].update_fpointer(identifier, mode)

    def __update_bpointer(self, position, identifier):
        self[position].bpointer = identifier

    def __getitem__(self, key):
        return self.nodes[self.get_index(key)]

    def __setitem__(self, key, item):
        self.nodes[self.get_index(key)] = item

    def __len__(self):
        return len(self.nodes)

    def __contains__(self, identifier):
        return [node.identifier for node in self.nodes
                if node.identifier is identifier]

if __name__ == "__main__":

    tree = Tree()
    tree.create_node("Harry", "harry")  # root node
    tree.create_node("Jane", "jane", parent = "harry")
    tree.create_node("Bill", "bill", parent = "harry")
    tree.create_node("Joe", "joe", parent = "jane")
    tree.create_node("Diane", "diane", parent = "jane")
    tree.create_node("George", "george", parent = "diane")
    tree.create_node("Mary", "mary", parent = "diane")
    tree.create_node("Jill", "jill", parent = "george")
    tree.create_node("Carol", "carol", parent = "jill")
    tree.create_node("Grace", "grace", parent = "bill")
    tree.create_node("Mark", "mark", parent = "jane")

    print("="*80)
    tree.show("harry")
    print("="*80)
    for node in tree.expand_tree("harry", mode=_WIDTH):
        print(node)
    print("="*80)

4

หากมีคนต้องการวิธีที่ง่ายกว่าในการทำทรีเป็นรายการซ้อนแบบวนซ้ำ (เนื่องจากชุดไม่สามารถแฮชได้):

[root, [child_1, [[child_11, []], [child_12, []]], [child_2, []]]]

ที่แต่ละสาขาเป็นคู่: [ object, [children] ]
และแต่ละใบเป็นคู่:[ object, [] ]

แต่ถ้าคุณต้องการชั้นเรียนด้วยวิธีการคุณสามารถใช้ anytree


1

คุณต้องการการดำเนินการใด มักจะมีทางออกที่ดีใน Python โดยใช้ dict หรือรายการที่มีโมดูล bisect

มีการนำต้นไม้จำนวนมากมาใช้ในPyPIและต้นไม้หลายชนิดแทบจะไม่สำคัญเลยที่จะใช้ตัวคุณเองใน Python บริสุทธิ์ อย่างไรก็ตามสิ่งนี้ไม่ค่อยจำเป็น


0

การนำต้นไม้อื่นมาใช้อย่างหลวม ๆ ตามคำตอบของ Bruno :

class Node:
    def __init__(self):
        self.name: str = ''
        self.children: List[Node] = []
        self.parent: Node = self

    def __getitem__(self, i: int) -> 'Node':
        return self.children[i]

    def add_child(self):
        child = Node()
        self.children.append(child)
        child.parent = self
        return child

    def __str__(self) -> str:
        def _get_character(x, left, right) -> str:
            if x < left:
                return '/'
            elif x >= right:
                return '\\'
            else:
                return '|'

        if len(self.children):
            children_lines: Sequence[List[str]] = list(map(lambda child: str(child).split('\n'), self.children))
            widths: Sequence[int] = list(map(lambda child_lines: len(child_lines[0]), children_lines))
            max_height: int = max(map(len, children_lines))
            total_width: int = sum(widths) + len(widths) - 1
            left: int = (total_width - len(self.name) + 1) // 2
            right: int = left + len(self.name)

            return '\n'.join((
                self.name.center(total_width),
                ' '.join(map(lambda width, position: _get_character(position - width // 2, left, right).center(width),
                             widths, accumulate(widths, add))),
                *map(
                    lambda row: ' '.join(map(
                        lambda child_lines: child_lines[row] if row < len(child_lines) else ' ' * len(child_lines[0]),
                        children_lines)),
                    range(max_height))))
        else:
            return self.name

และตัวอย่างของวิธีใช้:

tree = Node()
tree.name = 'Root node'
tree.add_child()
tree[0].name = 'Child node 0'
tree.add_child()
tree[1].name = 'Child node 1'
tree.add_child()
tree[2].name = 'Child node 2'
tree[1].add_child()
tree[1][0].name = 'Grandchild 1.0'
tree[2].add_child()
tree[2][0].name = 'Grandchild 2.0'
tree[2].add_child()
tree[2][1].name = 'Grandchild 2.1'
print(tree)

ซึ่งควรส่งออก:

                        โหนดรูท                        
     / / \              
โหนดย่อย 0 โหนดย่อย 1 โหนดย่อย 2        
                   | / \       
             Grandchild 1.0 Grandchild 2.0 Grandchild 2.1

0

ฉันแนะนำไลบรารีnetworkx

NetworkX เป็นแพ็กเกจ Python สำหรับการสร้างการจัดการและการศึกษาโครงสร้างพลศาสตร์และหน้าที่ของเครือข่ายที่ซับซ้อน

ตัวอย่างของการสร้างต้นไม้:

import networkx as nx
G = nx.Graph()
G.add_edge('A', 'B')
G.add_edge('B', 'C')
G.add_edge('B', 'D')
G.add_edge('A', 'E')
G.add_edge('E', 'F')

ฉันไม่แน่ใจว่าสิ่งที่คุณหมายถึงโดย " ต้นไม้ทั่วไป "
แต่ห้องสมุดช่วยให้แต่ละโหนดเป็นวัตถุ hashable ใด ๆและไม่มีข้อ จำกัด เกี่ยวกับจำนวนของเด็กแต่ละโหนดมี

ห้องสมุดยังให้อัลกอริทึมกราฟที่เกี่ยวข้องกับต้นไม้และความสามารถในการสร้างภาพ


-2

ถ้าคุณต้องการสร้างโครงสร้างข้อมูลแบบต้นไม้อันดับแรกคุณต้องสร้างวัตถุ treeElement หากคุณสร้างออบเจ็กต์ treeElement คุณจะสามารถตัดสินใจว่าทรีของคุณทำงานอย่างไร

ในการทำสิ่งต่อไปนี้คือคลาส TreeElement:

class TreeElement (object):

def __init__(self):
    self.elementName = None
    self.element = []
    self.previous = None
    self.elementScore = None
    self.elementParent = None
    self.elementPath = []
    self.treeLevel = 0

def goto(self, data):
    for child in range(0, len(self.element)):
        if (self.element[child].elementName == data):
            return self.element[child]

def add(self):

    single_element = TreeElement()
    single_element.elementName = self.elementName
    single_element.previous = self.elementParent
    single_element.elementScore = self.elementScore
    single_element.elementPath = self.elementPath
    single_element.treeLevel = self.treeLevel

    self.element.append(single_element)

    return single_element

ตอนนี้เราต้องใช้องค์ประกอบนี้เพื่อสร้างต้นไม้ฉันใช้ต้นไม้ A * ในตัวอย่างนี้

class AStarAgent(Agent):
# Initialization Function: Called one time when the game starts
def registerInitialState(self, state):
    return;

# GetAction Function: Called with every frame
def getAction(self, state):

    # Sorting function for the queue
    def sortByHeuristic(each_element):

        if each_element.elementScore:
            individual_score = each_element.elementScore[0][0] + each_element.treeLevel
        else:
            individual_score = admissibleHeuristic(each_element)

        return individual_score

    # check the game is over or not
    if state.isWin():
        print('Job is done')
        return Directions.STOP
    elif state.isLose():
        print('you lost')
        return Directions.STOP

    # Create empty list for the next states
    astar_queue = []
    astar_leaf_queue = []
    astar_tree_level = 0
    parent_tree_level = 0

    # Create Tree from the give node element
    astar_tree = TreeElement()
    astar_tree.elementName = state
    astar_tree.treeLevel = astar_tree_level
    astar_tree = astar_tree.add()

    # Add first element into the queue
    astar_queue.append(astar_tree)

    # Traverse all the elements of the queue
    while astar_queue:

        # Sort the element from the queue
        if len(astar_queue) > 1:
            astar_queue.sort(key=lambda x: sortByHeuristic(x))

        # Get the first node from the queue
        astar_child_object = astar_queue.pop(0)
        astar_child_state = astar_child_object.elementName

        # get all legal actions for the current node
        current_actions = astar_child_state.getLegalPacmanActions()

        if current_actions:

            # get all the successor state for these actions
            for action in current_actions:

                # Get the successor of the current node
                next_state = astar_child_state.generatePacmanSuccessor(action)

                if next_state:

                    # evaluate the successor states using scoreEvaluation heuristic
                    element_scored = [(admissibleHeuristic(next_state), action)]

                    # Increase the level for the child
                    parent_tree_level = astar_tree.goto(astar_child_state)
                    if parent_tree_level:
                        astar_tree_level = parent_tree_level.treeLevel + 1
                    else:
                        astar_tree_level += 1

                    # create tree for the finding the data
                    astar_tree.elementName = next_state
                    astar_tree.elementParent = astar_child_state
                    astar_tree.elementScore = element_scored
                    astar_tree.elementPath.append(astar_child_state)
                    astar_tree.treeLevel = astar_tree_level
                    astar_object = astar_tree.add()

                    # If the state exists then add that to the queue
                    astar_queue.append(astar_object)

                else:
                    # Update the value leaf into the queue
                    astar_leaf_state = astar_tree.goto(astar_child_state)
                    astar_leaf_queue.append(astar_leaf_state)

คุณสามารถเพิ่ม / ลบองค์ประกอบใด ๆ จากวัตถุ แต่ทำให้โครงสร้างมีความตั้งใจ


-4
def iterative_bfs(graph, start):
    '''iterative breadth first search from start'''
    bfs_tree = {start: {"parents":[], "children":[], "level":0}}
    q = [start]
    while q:
        current = q.pop(0)
        for v in graph[current]:
            if not v in bfs_tree:
                bfs_tree[v]={"parents":[current], "children":[], "level": bfs_tree[current]["level"] + 1}
                bfs_tree[current]["children"].append(v)
                q.append(v)
            else:
                if bfs_tree[v]["level"] > bfs_tree[current]["level"]:
                    bfs_tree[current]["children"].append(v)
                    bfs_tree[v]["parents"].append(current)

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