web-dev-qa-db-de.com

Wie implementiere ich einen binären Suchbaum in Python?

Das habe ich bis jetzt, aber es funktioniert nicht:

class Node:
    rChild,lChild,data = None,None,None

    def __init__(self,key):
        self.rChild = None
        self.lChild = None
        self.data = key

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

    def insert(self,node,someNumber):
        if node is None:
            node = Node(someNumber)
        else:
            if node.data > someNumber:
                self.insert(node.rchild,someNumber)
            else:
                self.insert(node.rchild, someNumber)
        return

def main():
    t = Tree()
    t.root = Node(4)
    t.root.rchild = Node(5)
    print t.root.data #this works
    print t.root.rchild.data #this works too
    t = Tree()
    t.insert(t.root,4)
    t.insert(t.root,5)
    print t.root.data #this fails
    print t.root.rchild.data #this fails too

if __== '__main__':
     main()
30
chochim

Hier ist ein kurzes Beispiel für eine binäre Einfügung:

class Node:
    def __init__(self, val):
        self.l_child = None
        self.r_child = None
        self.data = val

def binary_insert(root, node):
    if root is None:
        root = node
    else:
        if root.data > node.data:
            if root.l_child is None:
                root.l_child = node
            else:
                binary_insert(root.l_child, node)
        else:
            if root.r_child is None:
                root.r_child = node
            else:
                binary_insert(root.r_child, node)

def in_order_print(root):
    if not root:
        return
    in_order_print(root.l_child)
    print root.data
    in_order_print(root.r_child)

def pre_order_print(root):
    if not root:
        return        
    print root.data
    pre_order_print(root.l_child)
    pre_order_print(root.r_child)    

r = Node(3)
binary_insert(r, Node(7))
binary_insert(r, Node(1))
binary_insert(r, Node(5))

     3
    / \
   1   7
      /
     5

print "in order:"
in_order_print(r)

print "pre order"
pre_order_print(r)

in order:
1
3
5
7
pre order
3
1
7
5
50
DTing
class Node: 
    rChild,lChild,data = None,None,None

Das ist falsch - es macht Ihre Variablen Klassenvariablen - das heißt, jede Instanz von Node verwendet die gleichen Werte (das Ändern von rChild eines Knotens ändert es für alle Knoten!). Dies ist eindeutig nicht das, was Sie wollen. Versuchen

class Node: 
    def __init__(self, key):
        self.rChild = None
        self.lChild = None
        self.data = key

jetzt hat jeder Knoten einen eigenen Satz von Variablen. Dasselbe gilt für Ihre Definition von Baum.

class Tree:
    root,size = None,0    # <- lose this line!
    def __init__(self):
        self.root = None
        self.size = 0

Darüber hinaus sollte jede Klasse eine von der Klasse "object" abgeleitete Klasse "neuen Stils" sein und sich wieder mit dem Objekt verketten .__ init __ ():

class Node(object): 
    def __init__(self, data, rChild=None, lChild=None):
        super(Node,self).__init__()
        self.data   = data
        self.rChild = rChild
        self.lChild = lChild

class Tree(object):
    def __init__(self):
        super(Tree,self).__init__()
        self.root = None
        self.size = 0

Außerdem ist main () zu weit eingerückt - wie gezeigt, ist es eine Methode von Tree, die nicht aufgerufen werden kann, weil sie kein self -Argument akzeptiert.

Außerdem modifizieren Sie die Daten des Objekts direkt (t.root = Node(4)), wodurch die Kapselung zerstört wird (der ganze Punkt, an dem Klassen überhaupt vorhanden sind). Sie sollten etwas ähnlicher machen

def main():
    t = Tree()
    t.add(4)    # <- let the tree create a data Node and insert it
    t.add(5)
10
Hugh Bothwell
class BST:
    def __init__(self, val=None):
        self.left = None
        self.right = None
        self.val = val

    def __str__(self):
        return "[%s, %s, %s]" % (self.left, str(self.val), self.right)

    def isEmpty(self):
        return self.left == self.right == self.val == None

    def insert(self, val):
        if self.isEmpty():
            self.val = val
        Elif val < self.val:
            if self.left is None:
                self.left = BST(val)
            else:
                self.left.insert(val)
        else:
            if self.right is None:
                self.right = BST(val)
            else:
                self.right.insert(val)

a = BST(1)
a.insert(2)
a.insert(3)
a.insert(0)
print a
7
Aram Kocharyan
class Node:
    rChild,lChild,parent,data = None,None,None,0    

def __init__(self,key):
    self.rChild = None
    self.lChild = None
    self.parent = None
    self.data = key 

class Tree:
    root,size = None,0
    def __init__(self):
        self.root = None
        self.size = 0
    def insert(self,someNumber):
        self.size = self.size+1
        if self.root is None:
            self.root = Node(someNumber)
        else:
            self.insertWithNode(self.root, someNumber)    

    def insertWithNode(self,node,someNumber):
        if node.lChild is None and node.rChild is None:#external node
            if someNumber > node.data:
                newNode = Node(someNumber)
                node.rChild = newNode
                newNode.parent = node
            else:
                newNode = Node(someNumber)
                node.lChild = newNode
                newNode.parent = node
        else: #not external
            if someNumber > node.data:
                if node.rChild is not None:
                    self.insertWithNode(node.rChild, someNumber)
                else: #if empty node
                    newNode = Node(someNumber)
                    node.rChild = newNode
                    newNode.parent = node 
            else:
                if node.lChild is not None:
                    self.insertWithNode(node.lChild, someNumber)
                else:
                    newNode = Node(someNumber)
                    node.lChild = newNode
                    newNode.parent = node                    

    def printTree(self,someNode):
        if someNode is None:
            pass
        else:
            self.printTree(someNode.lChild)
            print someNode.data
            self.printTree(someNode.rChild)

def main():  
    t = Tree()
    t.insert(5)  
    t.insert(3)
    t.insert(7)
    t.insert(4)
    t.insert(2)
    t.insert(1)
    t.insert(6)
    t.printTree(t.root)

if __== '__main__':
    main()

Meine Lösung.

5
chochim

Die Tree.insert-Methode der Op qualifiziert sich für die Auszeichnung "Grosses Fehlverhalten der Woche" - sie fügt nichts ein. Es erstellt einen Knoten, der nicht mit einem anderen Knoten verbunden ist (nicht mit Knoten, an die er angehängt werden kann), und der erstellte Knoten wird bei der Rückkehr der Methode in den Papierkorb verschoben.

Für die Erbauung von @Hugh Bothwell:

>>> class Foo(object):
...    bar = None
...
>>> a = Foo()
>>> b = Foo()
>>> a.bar
>>> a.bar = 42
>>> b.bar
>>> b.bar = 666
>>> a.bar
42
>>> b.bar
666
>>>
5
John Machin

Ich finde die Lösungen auf dem insert-Teil etwas unbeholfen. Sie könnten die root-Referenz zurückgeben und etwas vereinfachen:

def binary_insert(root, node):
    if root is None:
        return node
    if root.data > node.data:
        root.l_child = binary_insert(root.l_child, node)
    else:
        root.r_child = binary_insert(root.r_child, node)
    return root
2
jlhonora

Nur etwas, um Ihnen beim Einstieg zu helfen. 

Eine (einfache Idee) der binären Baumsuche wäre wahrscheinlich in Python entsprechend den Zeilen implementiert:

def search(node, key):
    if node is None: return None  # key not found
    if key< node.key: return search(node.left, key)
    Elif key> node.key: return search(node.right, key)
    else: return node.value  # found key

Jetzt müssen Sie nur noch das Gerüst implementieren (Baumerstellung und Werteinfügungen) und fertig.

1
eat

Weitere Python-BST mit Sortierschlüssel

LEFT = 0
RIGHT = 1
VALUE = 2
SORT_KEY = -1

class BinarySearchTree(object):

    def __init__(self, sort_key=None):
        self._root = []  
        self._sort_key = sort_key
        self._len = 0  

def insert(self, val):
    if self._sort_key is None:
        sort_key = val // if no sort key, sort key is value
    else:
        sort_key = self._sort_key(val)

    node = self._root
    while node:
        if sort_key < node[_SORT_KEY]:
            node = node[LEFT]
        else:
            node = node[RIGHT]

    if sort_key is val:
        node[:] = [[], [], val]
    else:
        node[:] = [[], [], val, sort_key]
    self._len += 1

def minimum(self):
    return self._extreme_node(LEFT)[VALUE]

def maximum(self):
    return self._extreme_node(RIGHT)[VALUE]

def find(self, sort_key):
    return self._find(sort_key)[VALUE]

def _extreme_node(self, side):
    if not self._root:
        raise IndexError('Empty')
    node = self._root
    while node[side]:
        node = node[side]
    return node

def _find(self, sort_key):
    node = self._root
    while node:
        node_key = node[SORT_KEY]
        if sort_key < node_key:
            node = node[LEFT]
        Elif sort_key > node_key:
            node = node[RIGHT]
        else:
            return node
    raise KeyError("%r not found" % sort_key)
1
octoback

es ist einfach, eine BST mit zwei Klassen zu implementieren: 1. Node und 2. Tree Tree-Klasse ist nur für die Benutzeroberfläche gedacht, und tatsächliche Methoden werden in der Node-Klasse implementiert.

class Node():

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


    def _insert(self,data):
        if data == self.value:
            return False
        Elif data < self.value:
            if self.left:
                return self.left._insert(data)
            else:
                self.left = Node(data)
                return True
        else:
            if self.right:
                return self.right._insert(data)
            else:
                self.right = Node(data)
                return True

    def _inorder(self):
        if self:
            if self.left:
                self.left._inorder()
            print(self.value)
            if self.right:
                self.right._inorder()



class Tree():

    def __init__(self):
        self.root = None

    def insert(self,data):
        if self.root:
            return self.root._insert(data)
        else:
            self.root = Node(data)
            return True
    def inorder(self):
        if self.root is not None:
            return self.root._inorder()
        else:
            return False




if __name__=="__main__":
    a = Tree()
    a.insert(16)
    a.insert(8)
    a.insert(24)
    a.insert(6)
    a.insert(12)
    a.insert(19)
    a.insert(29)
    a.inorder()

Anordnungsfunktion zur Überprüfung, ob BST ordnungsgemäß implementiert ist.

1
nirav bharadiya

Hier ist eine kompakte, objektorientierte, rekursive Implementierung:

    class BTreeNode(object):
        def __init__(self, data):
            self.data = data
            self.rChild = None
            self.lChild = None

    def __str__(self):
        return (self.lChild.__str__() + '<-' if self.lChild != None else '') + self.data.__str__() + ('->' + self.rChild.__str__() if self.rChild != None else '')

    def insert(self, btreeNode):
        if self.data > btreeNode.data: #insert left
            if self.lChild == None:
                self.lChild = btreeNode
            else:
                self.lChild.insert(btreeNode)
        else: #insert right
            if self.rChild == None:
                self.rChild = btreeNode
            else:
                self.rChild.insert(btreeNode)


def main():
    btreeRoot = BTreeNode(5)
    print 'inserted %s:' %5, btreeRoot

    btreeRoot.insert(BTreeNode(7))
    print 'inserted %s:' %7, btreeRoot

    btreeRoot.insert(BTreeNode(3))
    print 'inserted %s:' %3, btreeRoot

    btreeRoot.insert(BTreeNode(1))
    print 'inserted %s:' %1, btreeRoot

    btreeRoot.insert(BTreeNode(2))
    print 'inserted %s:' %2, btreeRoot

    btreeRoot.insert(BTreeNode(4))
    print 'inserted %s:' %4, btreeRoot

    btreeRoot.insert(BTreeNode(6))
    print 'inserted %s:' %6, btreeRoot

Die Ausgabe des obigen main () ist:

inserted 5: 5
inserted 7: 5->7
inserted 3: 3<-5->7
inserted 1: 1<-3<-5->7
inserted 2: 1->2<-3<-5->7
inserted 4: 1->2<-3->4<-5->7
inserted 6: 1->2<-3->4<-5->6<-7
1
Pejvan

Eine andere Python BST-Lösung

class Node(object):
    def __init__(self, value):
        self.left_node = None
        self.right_node = None
        self.value = value

    def __str__(self):
        return "[%s, %s, %s]" % (self.left_node, self.value, self.right_node)

    def insertValue(self, new_value):
        """
        1. if current Node doesnt have value then assign to self
        2. new_value lower than current Node's value then go left
        2. new_value greater than current Node's value then go right
        :return:
        """
        if self.value:
            if new_value < self.value:
                # add to left
                if self.left_node is None:  # reached start add value to start
                    self.left_node = Node(new_value)
                else:
                    self.left_node.insertValue(new_value)  # search
            Elif new_value > self.value:
                # add to right
                if self.right_node is None:  # reached end add value to end
                    self.right_node = Node(new_value)
                else:
                    self.right_node.insertValue(new_value)  # search
        else:
            self.value = new_value

    def findValue(self, value_to_find):
        """
        1. value_to_find is equal to current Node's value then found
        2. if value_to_find is lower than Node's value then go to left
        3. if value_to_find is greater than Node's value then go to right
        """
        if value_to_find == self.value:
            return "Found"
        Elif value_to_find < self.value and self.left_node:
            return self.left_node.findValue(value_to_find)
        Elif value_to_find > self.value and self.right_node:
            return self.right_node.findValue(value_to_find)
        return "Not Found"

    def printTree(self):
        """
        Nodes will be in sequence
        1. Print LHS items
        2. Print value of node
        3. Print RHS items
        """
        if self.left_node:
            self.left_node.printTree()
        print(self.value),
        if self.right_node:
            self.right_node.printTree()

    def isEmpty(self):
        return self.left_node == self.right_node == self.value == None


def main():
    root_node = Node(12)
    root_node.insertValue(6)
    root_node.insertValue(3)
    root_node.insertValue(7)

    # should return 3 6 7 12
    root_node.printTree()

    # should return found
    root_node.findValue(7)
    # should return found
    root_node.findValue(3)
    # should return Not found
    root_node.findValue(24)

if __name__ == '__main__':
    main()
0
Umesh

Die akzeptierte Antwort vernachlässigt das Festlegen eines übergeordneten Attributs für jeden eingefügten Knoten, ohne den keine successor-Methode implementiert werden kann, die den Nachfolger in einem geordneten Baumlauf in O (h) Zeit findet. Dabei ist h die Höhe des Baums (im Gegensatz zu der für die Wanderung erforderlichen Zeit O (n)).

Hier ist eine Implementierung basierend auf dem Pseudocode in Cormen et al., Introduction to Algorithms, einschließlich der Zuweisung eines parent-Attributs und einer successor-Methode:

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


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

    def insert(self, z):
        y = None
        x = self.root
        while x is not None:
            y = x
            if z.key < x.key:
                x = x.left
            else:
                x = x.right
        z.parent = y
        if y is None:
            self.root = z       # Tree was empty
        Elif z.key < y.key:
            y.left = z
        else:
            y.right = z

    @staticmethod
    def minimum(x):
        while x.left is not None:
            x = x.left
        return x

    @staticmethod
    def successor(x):
        if x.right is not None:
            return Tree.minimum(x.right)
        y = x.parent
        while y is not None and x == y.right:
            x = y
            y = y.parent
        return y

Hier einige Tests, um zu zeigen, dass sich der Baum wie erwartet für das von DTing gegebene Beispiel verhält:

import pytest

@pytest.fixture
def tree():
    t = Tree()
    t.insert(Node(3))
    t.insert(Node(1))
    t.insert(Node(7))
    t.insert(Node(5))
    return t

def test_tree_insert(tree):
    assert tree.root.key == 3
    assert tree.root.left.key == 1
    assert tree.root.right.key == 7
    assert tree.root.right.left.key == 5

def test_tree_successor(tree):
    assert Tree.successor(tree.root.left).key == 3
    assert Tree.successor(tree.root.right.left).key == 7

if __== "__main__":
    pytest.main([__file__])
0
Kurt Peek

Hier ist eine funktionierende Lösung.

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

    def insert(self,data):
        if self.root == None:
            self.root = BST(data)
        Elif data > self.root:
            if self.right == None:
                self.right = BST(data)
            else:
                self.right.insert(data)
        Elif data < self.root:
            if self.left == None:
                self.left = BST(data)
            else:
                self.left.insert(data)

    def inordertraversal(self):
        if self.left != None:
            self.left.inordertraversal()
        print (self.root),
        if self.right != None:
            self.right.inordertraversal()

t = BST(4)
t.insert(1)
t.insert(7)
t.insert(3)
t.insert(6)
t.insert(2)
t.insert(5)
t.inordertraversal()
0
Sudhir

Das Problem oder zumindest ein Problem mit Ihrem Code ist hier: -

def insert(self,node,someNumber):
    if node is None:
        node = Node(someNumber)
    else:
        if node.data > someNumber:
            self.insert(node.rchild,someNumber)
        else:
            self.insert(node.rchild, someNumber)
    return

Sie sehen die Anweisung "if node.data> someNumber:" und die zugehörige "else:" - Anweisung haben beide denselben Code. Sie tun also dasselbe, ob die if -Anweisung wahr oder falsch ist.

Ich würde vorschlagen, dass Sie wahrscheinlich beabsichtigten, hier verschiedene Dinge zu tun. Vielleicht sollte einer davon self.insert (node.lchild, someNumber) sagen?

0
Michael

Der folgende Code ist grundlegend für die Antwort von @ DTing und das, was ich aus der Klasse lerne, die eine while-Schleife zum Einfügen verwendet (im Code angegeben). 

class Node:
    def __init__(self, val):
        self.l_child = None
        self.r_child = None
        self.data = val


def binary_insert(root, node):
    y = None
    x = root
    z = node
    #while loop here
    while x is not None:
        y = x
        if z.data < x.data:
            x = x.l_child
        else:
            x = x.r_child
    z.parent = y
    if y == None:
        root = z
    Elif z.data < y.data:
        y.l_child = z
    else:
        y.r_child = z


def in_order_print(root):
    if not root:
        return
    in_order_print(root.l_child)
    print(root.data)
    in_order_print(root.r_child)


r = Node(3)
binary_insert(r, Node(7))
binary_insert(r, Node(1))
binary_insert(r, Node(5))

in_order_print(r)
0
Liam