จะใช้ไบนารีทรีได้อย่างไร?


104

โครงสร้างข้อมูลใดที่ดีที่สุดที่สามารถใช้ในการสร้างไบนารีทรีใน Python ได้


2
โซลูชันจำนวนมากที่นี่กำลังใช้ BST แต่มีคำถามที่ถามถึงการใช้งาน Biner Tree
vikas mehta

อาจระบุว่าคุณต้องการอัลกอริทึมทรีใน Python ในชื่อคำถาม?
Ken Tran

คำตอบ:


97

นี่คือการนำต้นไม้ค้นหาไบนารีแบบเรียกซ้ำง่ายๆของฉันมาใช้

#!/usr/bin/python

class Node:
    def __init__(self, val):
        self.l = None
        self.r = None
        self.v = val

class Tree:
    def __init__(self):
        self.root = None

    def getRoot(self):
        return self.root

    def add(self, val):
        if self.root is None:
            self.root = Node(val)
        else:
            self._add(val, self.root)

    def _add(self, val, node):
        if val < node.v:
            if node.l is not None:
                self._add(val, node.l)
            else:
                node.l = Node(val)
        else:
            if node.r is not None:
                self._add(val, node.r)
            else:
                node.r = Node(val)

    def find(self, val):
        if self.root is not None:
            return self._find(val, self.root)
        else:
            return None

    def _find(self, val, node):
        if val == node.v:
            return node
        elif (val < node.v and node.l is not None):
            self._find(val, node.l)
        elif (val > node.v and node.r is not None):
            self._find(val, node.r)

    def deleteTree(self):
        # garbage collector will do this for us. 
        self.root = None

    def printTree(self):
        if self.root is not None:
            self._printTree(self.root)

    def _printTree(self, node):
        if node is not None:
            self._printTree(node.l)
            print(str(node.v) + ' ')
            self._printTree(node.r)

#     3
# 0     4
#   2      8
tree = Tree()
tree.add(3)
tree.add(4)
tree.add(0)
tree.add(8)
tree.add(2)
tree.printTree()
print(tree.find(3).v)
print(tree.find(10))
tree.deleteTree()
tree.printTree()

19
การใช้งานที่ดี ฉันแค่ที่นี่เพื่อชี้ให้เห็นสิ่งที่รูปแบบบาง python มักจะทำnode is not Noneแทน(node!=None)ไฟล์. นอกจากนี้คุณสามารถใช้__str__ฟังก์ชันแทนวิธี printTree
Jeff Mandell

2
นอกจากนี้ _find ของคุณควรจะเป็น: def _find(self, val, node): if(val == node.v): return node elif(val < node.v and node.l != None): return self._find(val, node.l) elif(val > node.v and node.r != None): return self._find(val, node.r)
darkhipo

4
นี้ไม่ได้เป็นต้นไม้ค้นหาแบบทวิภาคที่left<=root<=right?
Sagar Shah

3
tree.find (0), tree.find (2), tree.find (4), tree.find (8) ผลตอบแทนทั้งหมดไม่มี
Tony Wang

3
มีข้อผิดพลาดเล็กน้อยเมื่อคุณพยายามแทรกคีย์ที่มีอยู่แล้วมันจะลงไปที่โครงสร้างเพื่อสร้างโหนดใหม่ด้วยคีย์ที่ซ้ำกัน
Diego Gallegos

27
# simple binary tree
# in this implementation, a node is inserted between an existing node and the root


class BinaryTree():

    def __init__(self,rootid):
      self.left = None
      self.right = None
      self.rootid = rootid

    def getLeftChild(self):
        return self.left
    def getRightChild(self):
        return self.right
    def setNodeValue(self,value):
        self.rootid = value
    def getNodeValue(self):
        return self.rootid

    def insertRight(self,newNode):
        if self.right == None:
            self.right = BinaryTree(newNode)
        else:
            tree = BinaryTree(newNode)
            tree.right = self.right
            self.right = tree

    def insertLeft(self,newNode):
        if self.left == None:
            self.left = BinaryTree(newNode)
        else:
            tree = BinaryTree(newNode)
            tree.left = self.left
            self.left = tree


def printTree(tree):
        if tree != None:
            printTree(tree.getLeftChild())
            print(tree.getNodeValue())
            printTree(tree.getRightChild())



# test tree

def testTree():
    myTree = BinaryTree("Maud")
    myTree.insertLeft("Bob")
    myTree.insertRight("Tony")
    myTree.insertRight("Steven")
    printTree(myTree)

อ่านเพิ่มเติมได้ที่นี่: - นี่เป็นการใช้งานไบนารีทรีที่ง่ายมาก

นี่คือบทช่วยสอนที่ดีพร้อมคำถามระหว่างนั้น


2
รหัสในinsertLeftเสียและจะสร้างการวนซ้ำที่ไม่มีที่สิ้นสุดสำหรับความพยายามใด ๆ ที่จะวนซ้ำลงมาที่กิ่งซ้ายสุดของต้นไม้ไบนารี
กรงเล็บ

2
สามารถแก้ไขได้อย่างง่ายดายโดยการสลับบรรทัดต่อไปนี้ tree.left = self.left self.left = tree
AirelleJab

1
ลิงค์สุดท้ายเสีย คุณซ่อมได้หรือไม่.
Arjee

13

[สิ่งที่คุณต้องการสำหรับการสัมภาษณ์] คลาส Node คือโครงสร้างข้อมูลที่เพียงพอที่จะแสดงถึงต้นไม้ไบนารี

(แม้ว่าคำตอบอื่น ๆ ส่วนใหญ่จะถูกต้อง แต่ก็ไม่จำเป็นสำหรับต้นไม้ไบนารี: ไม่จำเป็นต้องขยายคลาสออบเจ็กต์ไม่จำเป็นต้องเป็น BST ไม่จำเป็นต้องนำเข้า deque)

class Node:

    def __init__(self, value = None):
        self.left  = None
        self.right = None
        self.value = value

นี่คือตัวอย่างของต้นไม้:

n1 = Node(1)
n2 = Node(2)
n3 = Node(3)
n1.left  = n2
n1.right = n3

ในตัวอย่างนี้ n1 คือรากของต้นไม้ที่มี n2, n3 เป็นลูกของมัน

ใส่คำอธิบายภาพที่นี่


สิ่งนี้เพิ่มอะไรนอกเหนือจากที่อธิบายไว้แล้วในคำตอบอื่น ๆ อีกมากมายหรือไม่
Sneftel

4
@Sneftel คำตอบอื่น ๆ มีความซับซ้อนมากกว่าสำหรับต้นไม้ไบนารี นี่คือชิ้นส่วนที่ต้องการซึ่งจำเป็นสำหรับการนำต้นไม้ไบนารีไปใช้ คำตอบอื่น ๆ ทำให้คนใหม่ ๆ เข้าใจยากเกินไปดังนั้นฉันจึงคิดว่าแค่โพสต์ขั้นต่ำสุดเปล่าเพื่อช่วยเหลือผู้คนใหม่ ๆ คำตอบอื่น ๆ บางส่วนเหมาะสำหรับบทความและเอกสารวารสาร) นี่เป็นส่วนที่ใครบางคนต้องการสำหรับการสัมภาษณ์ด้วยซอฟต์แวร์
apadana

3
เป็นการเพิ่มความเรียบง่ายซึ่งมีคุณค่า
pylang

2
ง่ายและมีเหตุผลมาก เยี่ยมมาก ฉันชอบมัน!
Apostolos

11

การใช้งาน BST อย่างง่ายใน Python

class TreeNode:
    def __init__(self, value):
        self.left = None
        self.right = None
        self.data = value

class Tree:
    def __init__(self):
        self.root = None

    def addNode(self, node, value):
        if(node==None):
            self.root = TreeNode(value)
        else:
            if(value<node.data):
                if(node.left==None):
                    node.left = TreeNode(value)
                else:
                    self.addNode(node.left, value)
            else:
                if(node.right==None):
                    node.right = TreeNode(value)
                else:
                    self.addNode(node.right, value)

    def printInorder(self, node):
        if(node!=None):
            self.printInorder(node.left)
            print(node.data)
            self.printInorder(node.right)

def main():
    testTree = Tree()
    testTree.addNode(testTree.root, 200)
    testTree.addNode(testTree.root, 300)
    testTree.addNode(testTree.root, 100)
    testTree.addNode(testTree.root, 30)
    testTree.printInorder(testTree.root)

2
คุณจบประโยคบางประโยคด้วยอัฒภาคและบางประโยคไม่มีอัฒภาค คุณช่วยอธิบายเหตุผลได้ไหม ป.ล. - ฉันเป็นมือใหม่ Python จึงถามคำถามพื้นฐานเช่นนี้
outlier229

@ outlier229 อัฒภาคทั้งหมดในโค้ดด้านบนเป็นทางเลือกการลบออกจะไม่เปลี่ยนแปลงอะไร ฉันเดาว่า Fox ใช้ในการเข้ารหัสภาษาเช่น C ++ หรือ Java ซึ่งต้องใช้เครื่องหมายอัฒภาคที่ท้ายบรรทัด นอกเหนือจากการใช้งานที่เป็นทางเลือกแล้วยังสามารถใช้อัฒภาคเพื่อเชื่อมประโยคคำสั่งในบรรทัดเดียวได้ ตัวอย่างเช่น a = 1; b = 2; c = 3 จะเป็นบรรทัดเดียวที่ถูกต้องใน python
PhysicsGuy

8

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

def _add(node, v):
    new = [v, [], []]
    if node:
        left, right = node[1:]
        if not left:
            left.extend(new)
        elif not right:
            right.extend(new)
        else:
            _add(left, v)
    else:
        node.extend(new)

def binary_tree(s):
    root = []
    for e in s:
        _add(root, e)
    return root

def traverse(n, order):
    if n:
        v = n[0]
        if order == 'pre':
            yield v
        for left in traverse(n[1], order):
            yield left
        if order == 'in':
            yield v
        for right in traverse(n[2], order):
            yield right
        if order == 'post':
            yield v

การสร้างต้นไม้จากสิ่งที่ทำซ้ำได้:

 >>> tree = binary_tree('A B C D E'.split())
 >>> print tree
 ['A', ['B', ['D', [], []], ['E', [], []]], ['C', [], []]]

ข้ามต้นไม้:

 >>> list(traverse(tree, 'pre')), list(traverse(tree, 'in')), list(traverse(tree, 'post'))
 (['A', 'B', 'D', 'E', 'C'],
  ['D', 'B', 'E', 'A', 'C'],
  ['D', 'E', 'B', 'C', 'A'])

ดีมาก! ฉันอดไม่ได้ที่จะแสดงความคิดเห็นว่าทรีผลลัพธ์ไม่ได้ถือค่าคงที่ที่องค์ประกอบทั้งหมดในทรีย่อยด้านซ้ายมีค่าน้อยกว่า v - คุณสมบัติที่สำคัญสำหรับทรีค้นหาทวิภาค (ใช่ฉันรู้ว่า OP ไม่ได้ขอ "แผนผังการค้นหา") อย่างไรก็ตาม FWIW สามารถทำได้ด้วยการปรับเปลี่ยนง่ายๆในการตรวจสอบใน _add () จากนั้นการข้ามผ่านตามลำดับจะให้รายการที่เรียงลำดับ
thayne

7

ฉันอดไม่ได้ที่จะสังเกตว่าคำตอบส่วนใหญ่ที่นี่คือการใช้งาน Binary Search Tree Binary Search Tree! = ทรีไบนารี

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

  • ต้นไม้ไบนารีไม่มีข้อ จำกัด ดังกล่าว Binary Tree เป็นโครงสร้างข้อมูลที่มีองค์ประกอบ 'คีย์' และลูกสองคนพูดว่า 'ซ้าย' และ 'ขวา'

  • Tree เป็นกรณีทั่วไปของ Binary Tree ที่แต่ละโหนดสามารถมีลูกได้ตามอำเภอใจ โดยปกติแล้วแต่ละโหนดจะมีองค์ประกอบ "ลูก" ซึ่งเป็นประเภทรายการ / อาร์เรย์

ตอนนี้เพื่อตอบคำถามของ OP ฉันกำลังรวมการใช้งาน Binary Tree ใน Python อย่างสมบูรณ์ โครงสร้างข้อมูลพื้นฐานที่จัดเก็บ BinaryTreeNode แต่ละตัวเป็นพจนานุกรมเนื่องจากมีการค้นหา O (1) ที่เหมาะสมที่สุด ฉันยังใช้การสำรวจเชิงลึกก่อนและแบบกว้างก่อน สิ่งเหล่านี้เป็นการดำเนินการทั่วไปบนต้นไม้

from collections import deque

class BinaryTreeNode:
    def __init__(self, key, left=None, right=None):
        self.key = key
        self.left = left
        self.right = right

    def __repr__(self):
        return "%s l: (%s) r: (%s)" % (self.key, self.left, self.right)

    def __eq__(self, other):
        if self.key == other.key and \
            self.right == other.right and \
                self.left == other.left:
            return True
        else:
            return False

class BinaryTree:
    def __init__(self, root_key=None):
        # maps from BinaryTreeNode key to BinaryTreeNode instance.
        # Thus, BinaryTreeNode keys must be unique.
        self.nodes = {}
        if root_key is not None:
            # create a root BinaryTreeNode
            self.root = BinaryTreeNode(root_key)
            self.nodes[root_key] = self.root

    def add(self, key, left_key=None, right_key=None):
        if key not in self.nodes:
            # BinaryTreeNode with given key does not exist, create it
            self.nodes[key] = BinaryTreeNode(key)
        # invariant: self.nodes[key] exists

        # handle left child
        if left_key is None:
            self.nodes[key].left = None
        else:
            if left_key not in self.nodes:
                self.nodes[left_key] = BinaryTreeNode(left_key)
            # invariant: self.nodes[left_key] exists
            self.nodes[key].left = self.nodes[left_key]

        # handle right child
        if right_key == None:
            self.nodes[key].right = None
        else:
            if right_key not in self.nodes:
                self.nodes[right_key] = BinaryTreeNode(right_key)
            # invariant: self.nodes[right_key] exists
            self.nodes[key].right = self.nodes[right_key]

    def remove(self, key):
        if key not in self.nodes:
            raise ValueError('%s not in tree' % key)
        # remove key from the list of nodes
        del self.nodes[key]
        # if node removed is left/right child, update parent node
        for k in self.nodes:
            if self.nodes[k].left and self.nodes[k].left.key == key:
                self.nodes[k].left = None
            if self.nodes[k].right and self.nodes[k].right.key == key:
                self.nodes[k].right = None
        return True

    def _height(self, node):
        if node is None:
            return 0
        else:
            return 1 + max(self._height(node.left), self._height(node.right))

    def height(self):
        return self._height(self.root)

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

    def __repr__(self):
        return str(self.traverse_inorder(self.root))

    def bfs(self, node):
        if not node or node not in self.nodes:
            return
        reachable = []    
        q = deque()
        # add starting node to queue
        q.append(node)
        while len(q):
            visit = q.popleft()
            # add currently visited BinaryTreeNode to list
            reachable.append(visit)
            # add left/right children as needed
            if visit.left:
                q.append(visit.left)
            if visit.right:
                q.append(visit.right)
        return reachable

    # visit left child, root, then right child
    def traverse_inorder(self, node, reachable=None):
        if not node or node.key not in self.nodes:
            return
        if reachable is None:
            reachable = []
        self.traverse_inorder(node.left, reachable)
        reachable.append(node.key)
        self.traverse_inorder(node.right, reachable)
        return reachable

    # visit left and right children, then root
    # root of tree is always last to be visited
    def traverse_postorder(self, node, reachable=None):
        if not node or node.key not in self.nodes:
            return
        if reachable is None:
            reachable = []
        self.traverse_postorder(node.left, reachable)
        self.traverse_postorder(node.right, reachable)
        reachable.append(node.key)
        return reachable

    # visit root, left, then right children
    # root is always visited first
    def traverse_preorder(self, node, reachable=None):
        if not node or node.key not in self.nodes:
            return
        if reachable is None:
            reachable = []
        reachable.append(node.key)
        self.traverse_preorder(node.left, reachable)
        self.traverse_preorder(node.right, reachable)
        return reachable

4

คุณไม่จำเป็นต้องมีสองคลาส

class Tree:
    val = None
    left = None
    right = None

    def __init__(self, val):
        self.val = val


    def insert(self, val):
        if self.val is not None:
            if val < self.val:
                if self.left is not None:
                    self.left.insert(val)
                else:
                    self.left = Tree(val)
            elif val > self.val:
                if self.right is not None:
                    self.right.insert(val)
                else:
                    self.right = Tree(val)
            else:
                return
        else:
            self.val = val
            print("new node added")

    def showTree(self):
        if self.left is not None:
            self.left.showTree()
        print(self.val, end = ' ')
        if self.right is not None:
            self.right.showTree()

7
จะดีกว่าถ้ามีสองคลาส นั่นคือการใช้งานที่ดีกว่า

1
@ user3022012 ความคิดเห็นของคุณไม่ถูกต้อง ตามความหมายต้นไม้ประกอบด้วยข้อมูลและต้นไม้ย่อย (สำหรับต้นไม้ไบนารีคือต้นไม้ย่อยสองต้น) ซึ่งก็คือต้นไม้เช่นกัน ไม่มีเหตุผลใด ๆ ที่จะทำให้โหนดรากแตกต่างกัน
กายราด

1
ผู้โพสต์เดิมขอเพียงการใช้งานต้นไม้ไบนารีไม่ใช่ต้นไม้ค้นหาแบบไบนารี...
กายอารัด

2

"Pythonic" อีกหน่อย?

class Node:
    def __init__(self, value):
        self.value = value
        self.left = None
        self.right = None

    def __repr__(self):
        return str(self.value)



class BST:
    def __init__(self):
        self.root = None

    def __repr__(self):
        self.sorted = []
        self.get_inorder(self.root)
        return str(self.sorted)

    def get_inorder(self, node):
        if node:
            self.get_inorder(node.left)
            self.sorted.append(str(node.value))
            self.get_inorder(node.right)

    def add(self, value):
        if not self.root:
            self.root = Node(value)
        else:
            self._add(self.root, value)

    def _add(self, node, value):
        if value <= node.value:
            if node.left:
                self._add(node.left, value)
            else:
                node.left = Node(value)
        else:
            if node.right:
                self._add(node.right, value)
            else:
                node.right = Node(value)



from random import randint

bst = BST()

for i in range(100):
    bst.add(randint(1, 1000))
print (bst)

2
#!/usr/bin/python

class BinaryTree:
    def __init__(self, left, right, data):
        self.left = left
        self.right = right
        self.data = data


    def pre_order_traversal(root):
        print(root.data, end=' ')

        if root.left != None:
            pre_order_traversal(root.left)

        if root.right != None:
            pre_order_traversal(root.right)

    def in_order_traversal(root):
        if root.left != None:
            in_order_traversal(root.left)
        print(root.data, end=' ')
        if root.right != None:
            in_order_traversal(root.right)

    def post_order_traversal(root):
        if root.left != None:
            post_order_traversal(root.left)
        if root.right != None:
            post_order_traversal(root.right)
        print(root.data, end=' ')

การส่งผ่านคำสั่งซื้อล่วงหน้าไม่ถูกต้อง: คุณต้องทดสอบแต่ละสาขาแยกกัน
Svante

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

อย่างที่เป็นอยู่ถ้าเด็กคนซ้ายเป็นไม่มีก็จะไม่มองลูกที่ถูกต้องด้วยซ้ำ
Svante

ฉันหมายถึงถ้าลูกทางซ้ายของต้นไม้ไบนารีไม่ใช่ไม่มีเราก็สามารถสันนิษฐานได้ว่าลูกที่ถูกต้องไม่ใช่ใครก็ได้เช่นกัน หากโหนดแตกกิ่งก้านออกเป็น 2 โหนดและมีเพียง 2 โหนดและโหนดทางซ้ายคือไม่มีโหนดที่ถูกต้องก็จะเป็นไม่มีเช่นกัน
eshanrh

2

Nodeระดับชั่นของโหนดที่เชื่อมต่อเป็นวิธีมาตรฐาน สิ่งเหล่านี้อาจมองเห็นได้ยาก

ได้รับแรงบันดาลใจจากบทความเรื่องPython Patterns - Implementing Graphsให้พิจารณาพจนานุกรมง่ายๆ:

ให้

ต้นไม้ไบนารี

               a
              / \
             b   c
            / \   \
           d   e   f

รหัส

สร้างพจนานุกรมของโหนดเฉพาะ :

tree = {
   "a": ["b", "c"],
   "b": ["d", "e"],
   "c": [None, "f"],
   "d": [None, None],
   "e": [None, None],
   "f": [None, None],
}

รายละเอียด

  • คู่คีย์ - ค่าแต่ละคู่เป็นโหนดที่ไม่ซ้ำกันชี้ไปที่ลูกของมัน
  • รายการ (หรือทูเพิล) มีลูกซ้าย / ขวาตามลำดับ
  • ด้วยคำสั่งที่มีการแทรกคำสั่งสมมติว่ารายการแรกคือรูท
  • วิธีการทั่วไปอาจเป็นฟังก์ชันที่กลายพันธุ์หรือข้ามผ่าน dict (ดูfind_all_paths())

ฟังก์ชันแบบต้นไม้มักจะรวมการดำเนินการทั่วไปดังต่อไปนี้:

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

ลองใช้การดำเนินการทั้งหมดนี้ ที่นี่เราแสดงให้เห็นถึงหนึ่งในฟังก์ชันเหล่านี้ - การส่งผ่าน BFS:

ตัวอย่าง

import collections as ct


def traverse(tree):
    """Yield nodes from a tree via BFS."""
    q = ct.deque()                                         # 1
    root = next(iter(tree))                                # 2
    q.append(root)

    while q:
        node = q.popleft()
        children = filter(None, tree.get(node))
        for n in children:                                 # 3 
            q.append(n)
        yield node

list(traverse(tree))
# ['a', 'b', 'c', 'd', 'e', 'f']

นี่คืออัลกอริทึมการค้นหาแบบกว้าง (ลำดับระดับ) ที่ใช้กับคำสั่งของโหนดและชายด์

  1. เริ่มต้นFIFO คิว เราใช้ a dequeแต่ a queueหรือlistงาน (อันหลังไม่มีประสิทธิภาพ)
  2. รับและจัดคิวโหนดรูท (สมมติว่ารูทเป็นรายการแรกใน dict, Python 3.6+)
  3. ออกคิวโหนดซ้ำจัดลำดับลูกและให้ค่าโหนด

ดูบทช่วยสอนเชิงลึกเกี่ยวกับต้นไม้


ข้อมูลเชิงลึก

สิ่งที่ยอดเยี่ยมเกี่ยวกับการข้ามผ่านโดยทั่วไปเราสามารถเปลี่ยนวิธีการทำซ้ำในการค้นหาเชิงลึกก่อน (DFS) ได้อย่างง่ายดายโดยการแทนที่คิวด้วยสแต็ก (หรือที่เรียกว่า LIFO Queue) นี่หมายความว่าเรา dequeue จากด้านเดียวกับที่เราจัดคิว DFS ให้เราค้นหาแต่ละสาขา

อย่างไร? เนื่องจากเราใช้ a dequeเราสามารถเลียนแบบสแตกได้โดยเปลี่ยนnode = q.popleft()เป็นnode = q.pop()(ขวา) ผลที่ได้คือขวาได้รับการสนับสนุนสั่งซื้อล่วงหน้า DFS['a', 'c', 'f', 'b', 'e', 'd'] :


1
import random

class TreeNode:
    def __init__(self, key):
        self.key = key
        self.left = None
        self.right = None
        self.p = None

class BinaryTree:
    def __init__(self):
        self.root = None

    def length(self):
        return self.size

    def inorder(self, node):
        if node == None:
            return None
        else:
            self.inorder(node.left)
            print node.key,
            self.inorder(node.right)

    def search(self, k):
        node = self.root
        while node != None:
            if node.key == k:
                return node
            if node.key > k:
                node = node.left
            else:
                node = node.right
        return None

    def minimum(self, node):
        x = None
        while node.left != None:
            x = node.left
            node = node.left
        return x

    def maximum(self, node):
        x = None
        while node.right != None:
            x = node.right
            node = node.right
        return x

    def successor(self, node):
        parent = None
        if node.right != None:
            return self.minimum(node.right)
        parent = node.p
        while parent != None and node == parent.right:
            node = parent
            parent = parent.p
        return parent

    def predecessor(self, node):
        parent = None
        if node.left != None:
            return self.maximum(node.left)
        parent = node.p
        while parent != None and node == parent.left:
            node = parent
            parent = parent.p
        return parent

    def insert(self, k):
        t = TreeNode(k)
        parent = None
        node = self.root
        while node != None:
            parent = node
            if node.key > t.key:
                node = node.left
            else:
                node = node.right
        t.p = parent
        if parent == None:
            self.root = t
        elif t.key < parent.key:
            parent.left = t
        else:
            parent.right = t
        return t


    def delete(self, node):
        if node.left == None:
            self.transplant(node, node.right)
        elif node.right == None:
            self.transplant(node, node.left)
        else:
            succ = self.minimum(node.right)
            if succ.p != node:
                self.transplant(succ, succ.right)
                succ.right = node.right
                succ.right.p = succ
            self.transplant(node, succ)
            succ.left = node.left
            succ.left.p = succ

    def transplant(self, node, newnode):
        if node.p == None:
            self.root = newnode
        elif node == node.p.left:
            node.p.left = newnode
        else:
            node.p.right = newnode
        if newnode != None:
            newnode.p = node.p

หลังจากรันสิ่งนี้โหนดใหม่ z, y, x, w, u, v บางครั้งอาจถูกกำหนดบางครั้งอาจมีข้อบกพร่องเช่นนี้พิมพ์ u.key AttributeError: วัตถุ 'NoneType' ไม่มีแอตทริบิวต์ 'คีย์' ฉันสงสัยว่า เพื่อแก้ไขขอบคุณ
water0

1

การใช้งานนี้สนับสนุนการดำเนินการแทรกค้นหาและลบโดยไม่ทำลายโครงสร้างของต้นไม้ นี่ไม่ใช่ต้นไม้แบน

# Class for construct the nodes of the tree. (Subtrees)
class Node:
def __init__(self, key, parent_node = None):
    self.left = None
    self.right = None
    self.key = key
    if parent_node == None:
        self.parent = self
    else:
        self.parent = parent_node

# Class with the  structure of the tree. 
# This Tree is not balanced.
class Tree:
def __init__(self):
    self.root = None

# Insert a single element
def insert(self, x):
    if(self.root == None):
        self.root = Node(x)
    else:
        self._insert(x, self.root)

def _insert(self, x, node):
    if(x < node.key):
        if(node.left == None):
            node.left = Node(x, node)
        else:
            self._insert(x, node.left)
    else:
        if(node.right == None):
            node.right = Node(x, node)
        else:
            self._insert(x, node.right)

# Given a element, return a node in the tree with key x. 
def find(self, x):
    if(self.root == None):
        return None
    else:
        return self._find(x, self.root)
def _find(self, x, node):
    if(x == node.key):
        return node
    elif(x < node.key):
        if(node.left == None):
            return None
        else:
            return self._find(x, node.left)
    elif(x > node.key):
        if(node.right == None):
            return None
        else:
            return self._find(x, node.right)

# Given a node, return the node in the tree with the next largest element.
def next(self, node):
    if node.right != None:
        return self._left_descendant(node.right)
    else:
        return self._right_ancestor(node)

def _left_descendant(self, node):
    if node.left == None:
        return node
    else:
        return self._left_descendant(node.left)

def _right_ancestor(self, node):
    if node.key <= node.parent.key:
        return node.parent
    else:
        return self._right_ancestor(node.parent)

# Delete an element of the tree
def delete(self, x):
    node = self.find(x)
    if node == None:
        print(x, "isn't in the tree")
    else:
        if node.right == None:
            if node.left == None:
                if node.key < node.parent.key:
                    node.parent.left = None
                    del node # Clean garbage
                else:
                    node.parent.right = None
                    del Node # Clean garbage
            else:
                node.key = node.left.key
                node.left = None
        else:
            x = self.next(node)
            node.key = x.key
            x = None


# tests
t = Tree()
t.insert(5)
t.insert(8)
t.insert(3)
t.insert(4)
t.insert(6)
t.insert(2)

t.delete(8)
t.delete(5)

t.insert(9)
t.insert(1)

t.delete(2)
t.delete(100)

# Remember: Find method return the node object. 
# To return a number use t.find(nº).key
# But it will cause an error if the number is not in the tree.
print(t.find(5)) 
print(t.find(8))
print(t.find(4))
print(t.find(6))
print(t.find(9))

1

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

คุณยังคงสามารถกำหนดคลาส Node เพื่อแทนโหนดในทรีได้ในที่สุดเมื่อจำเป็น แต่การเก็บไว้ในรูปแบบง่ายๆ [ค่า, ซ้าย, ขวา] ในรายการจะใช้หน่วยความจำครึ่งหนึ่งหรือน้อยกว่านั้น!

นี่คือตัวอย่างสั้น ๆ ของคลาส Binary Search Tree ที่จัดเก็บโหนดในอาร์เรย์ ให้ fonctions พื้นฐานเช่นเพิ่มลบค้นหา ...

"""
Basic Binary Search Tree class without recursion...
"""

__author__ = "@fbparis"

class Node(object):
    __slots__ = "value", "parent", "left", "right"
    def __init__(self, value, parent=None, left=None, right=None):
        self.value = value
        self.parent = parent
        self.left = left
        self.right = right

    def __repr__(self):
        return "<%s object at %s: parent=%s, left=%s, right=%s, value=%s>" % (self.__class__.__name__, hex(id(self)), self.parent, self.left, self.right, self.value)

class BinarySearchTree(object):
    __slots__ = "_tree"
    def __init__(self, *args):
        self._tree = []
        if args:
            for x in args[0]:
                self.add(x)

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

    def __repr__(self):
        return "<%s object at %s with %d nodes>" % (self.__class__.__name__, hex(id(self)), len(self))

    def __str__(self, nodes=None, level=0):
        ret = ""
        if nodes is None:
            if len(self):
                nodes = [0]
            else:
                nodes = []
        for node in nodes:
            if node is None:
                continue
            ret += "-" * level + " %s\n" % self._tree[node][0]
            ret += self.__str__(self._tree[node][2:4], level + 1)
        if level == 0:
            ret = ret.strip()
        return ret

    def __contains__(self, value):
        if len(self):
            node_index = 0
            while self._tree[node_index][0] != value:
                if value < self._tree[node_index][0]:
                    node_index = self._tree[node_index][2]
                else:
                    node_index = self._tree[node_index][3]
                if node_index is None:
                    return False
            return True
        return False

    def __eq__(self, other):
        return self._tree == other._tree

    def add(self, value):
        if len(self):
            node_index = 0
            while self._tree[node_index][0] != value:
                if value < self._tree[node_index][0]:
                    b = self._tree[node_index][2]
                    k = 2
                else:
                    b = self._tree[node_index][3]
                    k = 3
                if b is None:
                    self._tree[node_index][k] = len(self)
                    self._tree.append([value, node_index, None, None])
                    break
                node_index = b
        else:
            self._tree.append([value, None, None, None])

    def remove(self, value):
        if len(self):
            node_index = 0
            while self._tree[node_index][0] != value:
                if value < self._tree[node_index][0]:
                    node_index = self._tree[node_index][2]
                else:
                    node_index = self._tree[node_index][3]
                if node_index is None:
                    raise KeyError
            if self._tree[node_index][2] is not None:
                b, d = 2, 3
            elif self._tree[node_index][3] is not None:
                b, d = 3, 2
            else:
                i = node_index
                b = None
            if b is not None:
                i = self._tree[node_index][b]
                while self._tree[i][d] is not None:
                    i = self._tree[i][d]
                p = self._tree[i][1]
                b = self._tree[i][b]
                if p == node_index:
                    self._tree[p][5-d] = b
                else:
                    self._tree[p][d] = b
                if b is not None:
                    self._tree[b][1] = p
                self._tree[node_index][0] = self._tree[i][0]
            else:
                p = self._tree[i][1]
                if p is not None:
                    if self._tree[p][2] == i:
                        self._tree[p][2] = None
                    else:
                        self._tree[p][3] = None
            last = self._tree.pop()
            n = len(self)
            if i < n:
                self._tree[i] = last[:]
                if last[2] is not None:
                    self._tree[last[2]][1] = i
                if last[3] is not None:
                    self._tree[last[3]][1] = i
                if self._tree[last[1]][2] == n:
                    self._tree[last[1]][2] = i
                else:
                    self._tree[last[1]][3] = i
        else:
            raise KeyError

    def find(self, value):
        if len(self):
            node_index = 0
            while self._tree[node_index][0] != value:
                if value < self._tree[node_index][0]:
                    node_index = self._tree[node_index][2]
                else:
                    node_index = self._tree[node_index][3]
                if node_index is None:
                    return None
            return Node(*self._tree[node_index])
        return None

ฉันได้เพิ่มแอตทริบิวต์หลักเพื่อให้คุณสามารถลบโหนดใด ๆ และรักษาโครงสร้าง BST ได้

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

ฉันใช้เทคนิคนี้สำหรับเนื้อหาขั้นสูงเพื่อสร้างพจนานุกรมคำใหญ่ ๆ ด้วย radix trie ภายในและฉันสามารถแบ่งการใช้หน่วยความจำได้ 7-8 (คุณสามารถดูตัวอย่างได้ที่นี่: https://gist.github.com/fbparis / b3ddd5673b603b42c880974b23db7cda )


0

การนำต้นไม้ค้นหาไบนารีไปใช้งานได้ดีนำมาจากที่นี่ :

'''
A binary search Tree
'''
from __future__ import print_function
class Node:

    def __init__(self, label, parent):
        self.label = label
        self.left = None
        self.right = None
        #Added in order to delete a node easier
        self.parent = parent

    def getLabel(self):
        return self.label

    def setLabel(self, label):
        self.label = label

    def getLeft(self):
        return self.left

    def setLeft(self, left):
        self.left = left

    def getRight(self):
        return self.right

    def setRight(self, right):
        self.right = right

    def getParent(self):
        return self.parent

    def setParent(self, parent):
        self.parent = parent

class BinarySearchTree:

    def __init__(self):
        self.root = None

    def insert(self, label):
        # Create a new Node
        new_node = Node(label, None)
        # If Tree is empty
        if self.empty():
            self.root = new_node
        else:
            #If Tree is not empty
            curr_node = self.root
            #While we don't get to a leaf
            while curr_node is not None:
                #We keep reference of the parent node
                parent_node = curr_node
                #If node label is less than current node
                if new_node.getLabel() < curr_node.getLabel():
                #We go left
                    curr_node = curr_node.getLeft()
                else:
                    #Else we go right
                    curr_node = curr_node.getRight()
            #We insert the new node in a leaf
            if new_node.getLabel() < parent_node.getLabel():
                parent_node.setLeft(new_node)
            else:
                parent_node.setRight(new_node)
            #Set parent to the new node
            new_node.setParent(parent_node)      

    def delete(self, label):
        if (not self.empty()):
            #Look for the node with that label
            node = self.getNode(label)
            #If the node exists
            if(node is not None):
                #If it has no children
                if(node.getLeft() is None and node.getRight() is None):
                    self.__reassignNodes(node, None)
                    node = None
                #Has only right children
                elif(node.getLeft() is None and node.getRight() is not None):
                    self.__reassignNodes(node, node.getRight())
                #Has only left children
                elif(node.getLeft() is not None and node.getRight() is None):
                    self.__reassignNodes(node, node.getLeft())
                #Has two children
                else:
                    #Gets the max value of the left branch
                    tmpNode = self.getMax(node.getLeft())
                    #Deletes the tmpNode
                    self.delete(tmpNode.getLabel())
                    #Assigns the value to the node to delete and keesp tree structure
                    node.setLabel(tmpNode.getLabel())

    def getNode(self, label):
        curr_node = None
        #If the tree is not empty
        if(not self.empty()):
            #Get tree root
            curr_node = self.getRoot()
            #While we don't find the node we look for
            #I am using lazy evaluation here to avoid NoneType Attribute error
            while curr_node is not None and curr_node.getLabel() is not label:
                #If node label is less than current node
                if label < curr_node.getLabel():
                    #We go left
                    curr_node = curr_node.getLeft()
                else:
                    #Else we go right
                    curr_node = curr_node.getRight()
        return curr_node

    def getMax(self, root = None):
        if(root is not None):
            curr_node = root
        else:
            #We go deep on the right branch
            curr_node = self.getRoot()
        if(not self.empty()):
            while(curr_node.getRight() is not None):
                curr_node = curr_node.getRight()
        return curr_node

    def getMin(self, root = None):
        if(root is not None):
            curr_node = root
        else:
            #We go deep on the left branch
            curr_node = self.getRoot()
        if(not self.empty()):
            curr_node = self.getRoot()
            while(curr_node.getLeft() is not None):
                curr_node = curr_node.getLeft()
        return curr_node

    def empty(self):
        if self.root is None:
            return True
        return False

    def __InOrderTraversal(self, curr_node):
        nodeList = []
        if curr_node is not None:
            nodeList.insert(0, curr_node)
            nodeList = nodeList + self.__InOrderTraversal(curr_node.getLeft())
            nodeList = nodeList + self.__InOrderTraversal(curr_node.getRight())
        return nodeList

    def getRoot(self):
        return self.root

    def __isRightChildren(self, node):
        if(node == node.getParent().getRight()):
            return True
        return False

    def __reassignNodes(self, node, newChildren):
        if(newChildren is not None):
            newChildren.setParent(node.getParent())
        if(node.getParent() is not None):
            #If it is the Right Children
            if(self.__isRightChildren(node)):
                node.getParent().setRight(newChildren)
            else:
                #Else it is the left children
                node.getParent().setLeft(newChildren)

    #This function traversal the tree. By default it returns an
    #In order traversal list. You can pass a function to traversal
    #The tree as needed by client code
    def traversalTree(self, traversalFunction = None, root = None):
        if(traversalFunction is None):
            #Returns a list of nodes in preOrder by default
            return self.__InOrderTraversal(self.root)
        else:
            #Returns a list of nodes in the order that the users wants to
            return traversalFunction(self.root)

    #Returns an string of all the nodes labels in the list 
    #In Order Traversal
    def __str__(self):
        list = self.__InOrderTraversal(self.root)
        str = ""
        for x in list:
            str = str + " " + x.getLabel().__str__()
        return str

def InPreOrder(curr_node):
    nodeList = []
    if curr_node is not None:
        nodeList = nodeList + InPreOrder(curr_node.getLeft())
        nodeList.insert(0, curr_node.getLabel())
        nodeList = nodeList + InPreOrder(curr_node.getRight())
    return nodeList

def testBinarySearchTree():
    r'''
    Example
                  8
                 / \
                3   10
               / \    \
              1   6    14
                 / \   /
                4   7 13 
    '''

    r'''
    Example After Deletion
                  7
                 / \
                1   4

    '''
    t = BinarySearchTree()
    t.insert(8)
    t.insert(3)
    t.insert(6)
    t.insert(1)
    t.insert(10)
    t.insert(14)
    t.insert(13)
    t.insert(4)
    t.insert(7)

    #Prints all the elements of the list in order traversal
    print(t.__str__())

    if(t.getNode(6) is not None):
        print("The label 6 exists")
    else:
        print("The label 6 doesn't exist")

    if(t.getNode(-1) is not None):
        print("The label -1 exists")
    else:
        print("The label -1 doesn't exist")

    if(not t.empty()):
        print(("Max Value: ", t.getMax().getLabel()))
        print(("Min Value: ", t.getMin().getLabel()))

    t.delete(13)
    t.delete(10)
    t.delete(8)
    t.delete(3)
    t.delete(6)
    t.delete(14)

    #Gets all the elements of the tree In pre order
    #And it prints them
    list = t.traversalTree(InPreOrder, t.root)
    for x in list:
        print(x)

if __name__ == "__main__":
    testBinarySearchTree()

0

ฉันต้องการแสดงรูปแบบของวิธีการของ @ apadana ซึ่งมีประโยชน์มากกว่าเมื่อมีโหนดจำนวนมาก:

'''
Suppose we have the following tree
      10
    /    \
  11      9
 /  \     / \
7   12  15   8
'''
# Step 1 - Create nodes - Use a list instead of defining each node separately
nlist = [10,11,7,9,15,8,12]; n = []
for i in range(len(nlist)): n.append(Node(nlist[i]))

# Step 2 - Set each node position
n[0].left  = n[1]
n[1].left = n[2]
n[0].right = n[3]
n[3].left = n[4]
n[3].right = n[5]
n[1].right = n[6]

0
class Node:
    """
    single Node for tree
    """

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


class binaryTree:
    """
    binary tree implementation
    """

    def __init__(self):
        self.root = None

    def push(self, element, node=None):
        if node is None:
            node = self.root

        if self.root is None:
            self.root = Node(element)

        else:
            if element < node.data:
                if node.left is not None:
                    self.push(element, node.left)
                else:
                    node.left = Node(element)
            else:
                if node.right is not None:
                    self.push(element, node.right)
                else:
                    node.right = Node(element)

    def __str__(self):
        self.printInorder(self.root)
        return "\n"

    def printInorder(self, node):
        """
        print tree in inorder
        """
        if node is not None:
            self.printInorder(node.left)
            print(node.data)
            self.printInorder(node.right)


def main():
    """
    Main code and logic comes here
    """
    tree = binaryTree()
    tree.push(5)
    tree.push(3)
    tree.push(1)
    tree.push(3)
    tree.push(0)
    tree.push(2)
    tree.push(9)
    tree.push(10)
    print(tree)


if __name__ == "__main__":
    main()

-1

ไบนารีทรีใน Python

 class Tree(object):
    def __init__(self):
        self.data=None
        self.left=None
        self.right=None
    def insert(self, x, root):
        if root==None:
            t=node(x)
            t.data=x
            t.right=None
            t.left=None
            root=t
            return root
        elif x<root.data:
            root.left=self.insert(x, root.left)
        else:
            root.right=self.insert(x, root.right)
        return root

    def printTree(self, t):
        if t==None:
            return

        self.printTree(t.left)
        print t.data
        self.printTree(t.right)

class node(object):
    def __init__(self, x):
        self.x=x

bt=Tree()
root=None
n=int(raw_input())
a=[]
for i in range(n):
    a.append(int(raw_input()))
for i in range(n):
    root=bt.insert(a[i], root)
bt.printTree(root)

-1

นี่คือวิธีง่ายๆที่สามารถใช้ในการสร้างต้นไม้ไบนารีโดยใช้วิธีการเรียกซ้ำเพื่อแสดงต้นไม้ตามลำดับที่ถูกนำมาใช้ในโค้ดด้านล่าง

class Node(object):

    def __init__(self):
        self.left = None
        self.right = None
        self.value = None
    @property
    def get_value(self):
        return self.value

    @property
    def get_left(self):
        return self.left

    @property
    def get_right(self):
        return self.right

    @get_left.setter
    def set_left(self, left_node):
        self.left = left_node
    @get_value.setter
    def set_value(self, value):
        self.value = value
    @get_right.setter
    def set_right(self, right_node):
        self.right = right_node



    def create_tree(self):
        _node = Node() #creating new node.
        _x = input("Enter the node data(-1 for null)")
        if(_x == str(-1)): #for defining no child.
            return None
        _node.set_value = _x #setting the value of the node.
        print("Enter the left child of {}".format(_x))
        _node.set_left = self.create_tree() #setting the left subtree
        print("Enter the right child of {}".format(_x))
        _node.set_right = self.create_tree() #setting the right subtree.

        return _node

    def pre_order(self, root):
        if root is not None:
            print(root.get_value)
            self.pre_order(root.get_left)
            self.pre_order(root.get_right)

if __name__ == '__main__':
    node = Node()
    root_node = node.create_tree()
    node.pre_order(root_node)

รหัสนำมาจาก: Binary Tree ใน Python

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