Schöne Umsetzung. Ich bin nur hier, um auf einige Stilsachen hinzuweisen . Python tut normalerweise node is not Noneanstelle von Ihrem (node!=None). Sie können die __str__Funktion auch anstelle der printTree-Methode verwenden.
Jeff Mandell
2
Außerdem sollte Ihr _find wahrscheinlich sein: 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
Ist das nicht ein binärer Suchbaum wo left<=root<=right?
Sagar Shah
3
tree.find (0), tree.find (2), tree.find (4), tree.find (8) geben alle None zurück.
Tony Wang
3
Es gibt einen kleinen Fehler: Wenn Sie versuchen, einen vorhandenen Schlüssel einzufügen, wird der Baum nach unten verschoben, um einen neuen Knoten mit einem doppelten Schlüssel zu erstellen.
Diego Gallegos
27
# simple binary tree# in this implementation, a node is inserted between an existing node and the rootclassBinaryTree():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 treedef testTree():
myTree =BinaryTree("Maud")
myTree.insertLeft("Bob")
myTree.insertRight("Tony")
myTree.insertRight("Steven")
printTree(myTree)
Lesen Sie hier mehr darüber: - Dies ist eine sehr einfache Implementierung eines Binärbaums.
Dies ist ein schönes Tutorial mit Fragen dazwischen
Der Code in insertLeftist gebrochen und erzeugt eine Endlosschleife bei jedem Versuch, den am weitesten links liegenden Zweig des Binärbaums rekursiv zu durchlaufen
Talonmies
2
Es kann leicht durch Vertauschen der folgenden Zeilen behoben werden: tree.left = self.left self.left = tree
AirelleJab
1
Der letzte Link ist defekt. Kannst du das Reparieren.
Arjee
13
[Was Sie für Interviews benötigen] Eine Knotenklasse ist die ausreichende Datenstruktur, um einen Binärbaum darzustellen.
(Während andere Antworten meistens korrekt sind, sind sie für einen Binärbaum nicht erforderlich: Keine Notwendigkeit, die Objektklasse zu erweitern, keine Notwendigkeit, eine BST zu sein, keine Notwendigkeit, Deque zu importieren).
classNode:def __init__(self, value =None):
self.left =None
self.right =None
self.value = value
Fügt dies etwas hinzu, das über das hinausgeht, was bereits in den vielen anderen Antworten beschrieben wurde?
Sneftel
4
@Sneftel Andere Antworten sind für einen Binärbaum überentwickelt. Dies ist das erforderliche Teil, das für eine Implementierung eines Binärbaums benötigt wird. Andere Antworten machen es neuen Menschen zu schwer zu verstehen, deshalb dachte ich, ich poste nur das Nötigste, um neueren Menschen zu helfen. Einige der anderen Antworten sind gut für Artikel und Zeitschriftenartikel;) Dies ist auch das Stück, das jemand für Software-Interviews benötigt.
Sie haben einige Sätze mit einem Semikolon und einige ohne Semikolon beendet. Könnten Sie bitte den Grund dafür erklären? PS: Ich bin ein Python-Anfänger, deshalb stelle ich eine so grundlegende Frage.
Ausreißer229
@ outlier229 Alle Semikolons im obigen Code sind optional. Wenn Sie sie entfernen, ändert sich nichts. Ich vermute, dass Fox einfach daran gewöhnt ist, eine Sprache wie C ++ oder Java zu codieren, für die das Semikolon am Ende der Zeile erforderlich ist. Abgesehen von dieser optionalen Verwendung können Semikolons verwendet werden, um Anweisungen in einer einzelnen Zeile zu verketten. Zum Beispiel a = 1; b = 2; c = 3 wäre eine gültige einzelne Zeile in Python.
PhysikGuy
8
Eine sehr schnelle und schmutzige Methode zum Implementieren eines Binärbaums mithilfe von Listen. Weder das effizienteste, noch geht es allzu gut mit Nullwerten um. Aber es ist sehr transparent (zumindest für mich):
def _add(node, v):
new =[v,[],[]]if node:
left, right = node[1:]ifnot left:
left.extend(new)elifnot 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
Erstellen eines Baums aus einem iterierbaren Element:
>>> tree = binary_tree('A B C D E'.split())>>>print tree
['A',['B',['D',[],[]],['E',[],[]]],['C',[],[]]]
Sehr schön! Ich konnte nicht anders als zu kommentieren, dass der resultierende Baum nicht die Invariante enthält, dass alle Elemente im linken Teilbaum kleiner als v sind. - Eine Eigenschaft, die für binäre Suchbäume wichtig ist. (Ja, mir ist klar, dass OP nicht nach einem "Suchbaum" gefragt hat.) FWIW kann dies jedoch mit einer einfachen Änderung der Prüfung in _add () erfolgen. Dann gibt Ihre Inorder Traversal eine sortierte Liste.
Thayne
6
Ich kann nicht anders, als zu bemerken, dass die meisten Antworten hier einen binären Suchbaum implementieren. Binärer Suchbaum! = Binärer Baum.
Ein binärer Suchbaum hat eine sehr spezifische Eigenschaft: Für jeden Knoten X ist der Schlüssel von X größer als der Schlüssel eines Nachkommen seines linken Kindes und kleiner als der Schlüssel eines Nachkommen seines rechten Kindes.
Ein Binärbaum unterwirft keine solche Einschränkung. Ein Binärbaum ist einfach eine Datenstruktur mit einem 'Schlüssel'-Element und zwei untergeordneten Elementen, z. B.' links 'und' rechts '.
Ein Baum ist ein noch allgemeinerer Fall eines Binärbaums, bei dem jeder Knoten eine beliebige Anzahl von untergeordneten Knoten haben kann. Normalerweise hat jeder Knoten ein untergeordnetes Element vom Typ Liste / Array.
Um die Frage des OP zu beantworten, füge ich jetzt eine vollständige Implementierung eines Binärbaums in Python hinzu. Die zugrunde liegende Datenstruktur, in der jeder BinaryTreeNode gespeichert ist, ist ein Wörterbuch, da sie optimale O (1) -Suchen bietet. Ich habe auch Travals mit der Tiefe und der Breite zuerst implementiert. Dies sind sehr häufige Operationen, die an Bäumen durchgeführt werden.
from collections import deque
classBinaryTreeNode: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:returnTrueelse:returnFalseclassBinaryTree:def __init__(self, root_key=None):# maps from BinaryTreeNode key to BinaryTreeNode instance.# Thus, BinaryTreeNode keys must be unique.
self.nodes ={}if root_key isnotNone:# 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 notin self.nodes:# BinaryTreeNode with given key does not exist, create it
self.nodes[key]=BinaryTreeNode(key)# invariant: self.nodes[key] exists# handle left childif left_key isNone:
self.nodes[key].left =Noneelse:if left_key notin 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 childif right_key ==None:
self.nodes[key].right =Noneelse:if right_key notin 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 notin self.nodes:raiseValueError('%s not in tree'% key)# remove key from the list of nodesdel self.nodes[key]# if node removed is left/right child, update parent nodefor k in self.nodes:if self.nodes[k].left and self.nodes[k].left.key == key:
self.nodes[k].left =Noneif self.nodes[k].right and self.nodes[k].right.key == key:
self.nodes[k].right =NonereturnTruedef _height(self, node):if node isNone:return0else:return1+ 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):ifnot node or node notin 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 neededif visit.left:
q.append(visit.left)if visit.right:
q.append(visit.right)return reachable
# visit left child, root, then right childdef traverse_inorder(self, node, reachable=None):ifnot node or node.key notin self.nodes:returnif reachable isNone:
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 visiteddef traverse_postorder(self, node, reachable=None):ifnot node or node.key notin self.nodes:returnif reachable isNone:
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 firstdef traverse_preorder(self, node, reachable=None):ifnot node or node.key notin self.nodes:returnif reachable isNone:
reachable =[]
reachable.append(node.key)
self.traverse_preorder(node.left, reachable)
self.traverse_preorder(node.right, reachable)return reachable
Es ist besser, zwei Klassen zu haben. Das ist eine bessere Implementierung
1
@ user3022012 dein Kommentar ist einfach falsch. Per Definition besteht ein Baum aus Daten und Unterbäumen (beim Binärbaum sind es zwei Unterbäume), die auch Bäume sind. Kein Grund, den Wurzelknoten anders zu baumeln.
Guyarad
1
das ursprüngliche Plakat nur für eine gefragt binäre Baum - Implementierung und nicht ein binärer Suchbaum ...
Die Vorbestellungsdurchquerung ist falsch: Sie müssen jeden Zweig einzeln testen.
Svante
Ich denke, Sie müssen jede Filiale nur bei Bestellung und Nachbestellung einzeln testen. Die von mir geschriebene Vorbestellungsmethode liefert das richtige Ergebnis. Können Sie mir sagen, in welchem Fall diese Methode brechen wird? Lassen Sie mich jedoch beide Zweige getrennt testen, wie ich es für Nachbestellung und In-Order getan habe
Shanks
So wie es war, wenn das linke Kind keines wäre, würde es nicht einmal das rechte Kind ansehen.
Svante
Ich meine, wenn das linke Kind eines Binärbaums keines ist, können wir davon ausgehen, dass das rechte Kind auch keines ist. Wenn ein Knoten in 2 und nur 2 Knoten verzweigt und der linke Knoten None ist, ist der rechte ebenfalls None.
Eshanrh
2
Eine auf NodeKlassen basierende Klasse verbundener Knoten ist ein Standardansatz. Diese können schwer zu visualisieren sein.
Betrachten Sie ein einfaches Wörterbuch, das aus einem Aufsatz über Python-Muster - Implementieren von Diagrammen motiviert ist :
Gegeben
Ein binärer Baum
a
/ \
b c
/ \ \
d e f
Code
Erstellen Sie ein Wörterbuch mit eindeutigen Knoten:
tree ={"a":["b","c"],"b":["d","e"],"c":[None,"f"],"d":[None,None],"e":[None,None],"f":[None,None],}
Einzelheiten
Jedes Schlüssel-Wert-Paar ist ein eindeutiger Knoten , der auf seine untergeordneten Knoten zeigt.
Eine Liste (oder ein Tupel) enthält ein geordnetes Paar linker / rechter Kinder.
Mit einem Diktat, das die Einfügung angeordnet hat der erste Eintrag ist die Wurzel, .
Gängige Methoden können Funktionen sein, die das Diktat mutieren oder durchlaufen (siehe find_all_paths()).
Baumbasierte Funktionen umfassen häufig die folgenden allgemeinen Operationen:
Traverse : Geben Sie jeden Knoten in einer bestimmten Reihenfolge ab (normalerweise von links nach rechts).
Breitensuche (BFS): Ebenen durchlaufen
Tiefensuche (DFS): Zweige zuerst durchqueren (Pre- / In / Post-Order)
Einfügen : Fügen Sie dem Baum abhängig von der Anzahl der untergeordneten Elemente einen Knoten hinzu
Entfernen : Entfernen Sie einen Knoten abhängig von der Anzahl der untergeordneten Knoten
Update : Führen Sie fehlende Knoten von einem Baum zum anderen zusammen
visit : Geben Sie den Wert eines durchquerten Knotens an
Versuchen Sie, alle diese Vorgänge zu implementieren. Hier zeigen wir eine dieser Funktionen - eine BFS-Durchquerung:
Beispiel
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
Initialisieren Sie eine FIFO-Warteschlange . Wir verwenden ein deque, aber ein queueoder ein listWerk (letzteres ist ineffizient).
Holen Sie sich den Stammknoten und stellen Sie ihn in die Warteschlange (vorausgesetzt, der Stamm ist der erste Eintrag im Diktat Python 3.6+).
Einen Knoten iterativ aus der Warteschlange entfernen, seine untergeordneten Knoten in die Warteschlange stellen und den Knotenwert ergeben.
Siehe auch dieses ausführliche Tutorial zu Bäumen.
Einblick
Etwas Großartiges an Durchläufen im Allgemeinen ist, dass wir den letztgenannten iterativen Ansatz für die Tiefensuche (DFS) leicht ändern können, indem wir einfach die Warteschlange durch einen Stapel ersetzen (auch bekannt als LIFO-Warteschlange) . Dies bedeutet einfach, dass wir uns von derselben Seite aus der Warteschlange entfernen, von der wir uns in die Warteschlange stellen. Mit DFS können wir jeden Zweig durchsuchen.
Wie? Da wir a verwenden deque, können wir einen Stapel emulieren, indem wir node = q.popleft()zu node = q.pop()(rechts) wechseln . Das Ergebnis ist eine rechtsbegünstigte, vorbestellte DFS : ['a', 'c', 'f', 'b', 'e', 'd'].
Nachdem dies ausgeführt wurde, konnten die neuen Knoten z, y, x, w, u, v manchmal zugewiesen werden, manchmal hatten sie Fehler wie folgt: print u.key AttributeError: 'NoneType'-Objekt hat kein Attribut' key 'Ich frage mich, wie um es zu reparieren, danke
water0
1
Diese Implementierung unterstützt Einfüge-, Such- und Löschvorgänge, ohne die Struktur des Baums zu zerstören. Dies ist kein Banlanced-Baum.
# Class for construct the nodes of the tree. (Subtrees)classNode: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.classTree:def __init__(self):
self.root =None# Insert a single elementdef 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):returnNoneelse: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):returnNoneelse:return self._find(x, node.left)elif(x > node.key):if(node.right ==None):returnNoneelse: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 treedef 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 =Nonedel node # Clean garbageelse:
node.parent.right =NonedelNode# Clean garbageelse:
node.key = node.left.key
node.left =Noneelse:
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))
Ich weiß, dass bereits viele gute Lösungen veröffentlicht wurden, aber ich habe normalerweise einen anderen Ansatz für Binärbäume: Es ist besser, mit einer Knotenklasse zu arbeiten und sie direkt zu implementieren, aber wenn Sie viele Knoten haben, kann dies sehr speichergierig werden, also ich Schlagen Sie vor, eine Komplexitätsebene hinzuzufügen, die Knoten in einer Python-Liste zu speichern und anschließend ein Baumverhalten nur anhand der Liste zu simulieren.
Sie können weiterhin eine Knotenklasse definieren, um die Knoten im Baum bei Bedarf endgültig darzustellen. Wenn Sie sie jedoch in einer einfachen Form [Wert, links, rechts] in einer Liste aufbewahren, wird die Hälfte des Speichers oder weniger benötigt!
Hier ist ein kurzes Beispiel für eine binäre Suchbaumklasse, in der die Knoten in einem Array gespeichert sind. Es bietet grundlegende Funktionen wie Hinzufügen, Entfernen, Suchen ...
"""
Basic Binary Search Tree class without recursion...
"""
__author__ ="@fbparis"classNode(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)classBinarySearchTree(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 isNone:if len(self):
nodes =[0]else:
nodes =[]for node in nodes:if node isNone: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 =0while 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 isNone:returnFalsereturnTruereturnFalsedef __eq__(self, other):return self._tree == other._tree
def add(self, value):if len(self):
node_index =0while self._tree[node_index][0]!= value:if value < self._tree[node_index][0]:
b = self._tree[node_index][2]
k =2else:
b = self._tree[node_index][3]
k =3if b isNone:
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 =0while 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 isNone:raiseKeyErrorif self._tree[node_index][2]isnotNone:
b, d =2,3elif self._tree[node_index][3]isnotNone:
b, d =3,2else:
i = node_index
b =Noneif b isnotNone:
i = self._tree[node_index][b]while self._tree[i][d]isnotNone:
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 isnotNone:
self._tree[b][1]= p
self._tree[node_index][0]= self._tree[i][0]else:
p = self._tree[i][1]if p isnotNone:if self._tree[p][2]== i:
self._tree[p][2]=Noneelse:
self._tree[p][3]=None
last = self._tree.pop()
n = len(self)if i < n:
self._tree[i]= last[:]if last[2]isnotNone:
self._tree[last[2]][1]= i
if last[3]isnotNone:
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:raiseKeyErrordef find(self, value):if len(self):
node_index =0while 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 isNone:returnNonereturnNode(*self._tree[node_index])returnNone
Ich habe ein übergeordnetes Attribut hinzugefügt, damit Sie jeden Knoten entfernen und die BST-Struktur beibehalten können.
Entschuldigen Sie die Lesbarkeit, insbesondere die Funktion "Entfernen". Grundsätzlich entfernen wir beim Entfernen eines Knotens das Baumarray und ersetzen es durch das letzte Element (außer wenn wir den letzten Knoten entfernen wollten). Um die BST-Struktur beizubehalten, wird der entfernte Knoten durch das Maximum seiner linken Kinder oder das Minimum seiner rechten Kinder ersetzt, und einige Operationen müssen ausgeführt werden, um die Indizes gültig zu halten, aber es ist schnell genug.
Ich habe diese Technik für fortgeschrittenere Dinge verwendet, um einige Wörterbücher mit großen Wörtern mit einem internen Radix-Versuch zu erstellen, und ich konnte den Speicherverbrauch durch 7-8 teilen (ein Beispiel finden Sie hier: https://gist.github.com/fbparis / b3ddd5673b603b42c880974b23db7cda )
Eine gute Implementierung des binären Suchbaums von hier :
'''
A binary search Tree
'''from __future__ import print_function
classNode: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
classBinarySearchTree:def __init__(self):
self.root =Nonedef insert(self, label):# Create a new Node
new_node =Node(label,None)# If Tree is emptyif self.empty():
self.root = new_node
else:#If Tree is not empty
curr_node = self.root
#While we don't get to a leafwhile curr_node isnotNone:#We keep reference of the parent node
parent_node = curr_node
#If node label is less than current nodeif 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 leafif 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 existsif(node isnotNone):#If it has no childrenif(node.getLeft()isNoneand node.getRight()isNone):
self.__reassignNodes(node,None)
node =None#Has only right childrenelif(node.getLeft()isNoneand node.getRight()isnotNone):
self.__reassignNodes(node, node.getRight())#Has only left childrenelif(node.getLeft()isnotNoneand node.getRight()isNone):
self.__reassignNodes(node, node.getLeft())#Has two childrenelse:#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 emptyif(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 errorwhile curr_node isnotNoneand curr_node.getLabel()isnot label:#If node label is less than current nodeif 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 isnotNone):
curr_node = root
else:#We go deep on the right branch
curr_node = self.getRoot()if(not self.empty()):while(curr_node.getRight()isnotNone):
curr_node = curr_node.getRight()return curr_node
def getMin(self, root =None):if(root isnotNone):
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()isnotNone):
curr_node = curr_node.getLeft()return curr_node
def empty(self):if self.root isNone:returnTruereturnFalsedef __InOrderTraversal(self, curr_node):
nodeList =[]if curr_node isnotNone:
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()):returnTruereturnFalsedef __reassignNodes(self, node, newChildren):if(newChildren isnotNone):
newChildren.setParent(node.getParent())if(node.getParent()isnotNone):#If it is the Right Childrenif(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 codedef traversalTree(self, traversalFunction =None, root =None):if(traversalFunction isNone):#Returns a list of nodes in preOrder by defaultreturn self.__InOrderTraversal(self.root)else:#Returns a list of nodes in the order that the users wants toreturn traversalFunction(self.root)#Returns an string of all the nodes labels in the list #In Order Traversaldef __str__(self):
list = self.__InOrderTraversal(self.root)
str =""for x in list:
str = str +" "+ x.getLabel().__str__()return str
defInPreOrder(curr_node):
nodeList =[]if curr_node isnotNone:
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 traversalprint(t.__str__())if(t.getNode(6)isnotNone):print("The label 6 exists")else:print("The label 6 doesn't exist")if(t.getNode(-1)isnotNone):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()
Ich möchte eine Variation der Methode von @ apadana zeigen, die bei einer beträchtlichen Anzahl von Knoten nützlicher ist:
'''
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]
Hier ist eine einfache Lösung, mit der ein Binärbaum mithilfe eines rekursiven Ansatzes erstellt werden kann, um den Baum in der Reihenfolge anzuzeigen, in der die Durchquerung im folgenden Code verwendet wurde.
classNode(object):def __init__(self):
self.left =None
self.right =None
self.value =None@propertydef get_value(self):return self.value
@propertydef get_left(self):return self.left
@propertydef 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.returnNone
_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 subtreeprint("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 isnotNone: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)
Antworten:
Hier ist meine einfache rekursive Implementierung des binären Suchbaums.
quelle
node is not None
anstelle von Ihrem(node!=None)
. Sie können die__str__
Funktion auch anstelle der printTree-Methode verwenden.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)
left<=root<=right
?Lesen Sie hier mehr darüber: - Dies ist eine sehr einfache Implementierung eines Binärbaums.
Dies ist ein schönes Tutorial mit Fragen dazwischen
quelle
insertLeft
ist gebrochen und erzeugt eine Endlosschleife bei jedem Versuch, den am weitesten links liegenden Zweig des Binärbaums rekursiv zu durchlaufen[Was Sie für Interviews benötigen] Eine Knotenklasse ist die ausreichende Datenstruktur, um einen Binärbaum darzustellen.
(Während andere Antworten meistens korrekt sind, sind sie für einen Binärbaum nicht erforderlich: Keine Notwendigkeit, die Objektklasse zu erweitern, keine Notwendigkeit, eine BST zu sein, keine Notwendigkeit, Deque zu importieren).
Hier ist ein Beispiel eines Baumes:
In diesem Beispiel ist n1 die Wurzel des Baums mit n2, n3 als untergeordneten Elementen.
quelle
Einfache Implementierung von BST in Python
quelle
Eine sehr schnelle und schmutzige Methode zum Implementieren eines Binärbaums mithilfe von Listen. Weder das effizienteste, noch geht es allzu gut mit Nullwerten um. Aber es ist sehr transparent (zumindest für mich):
Erstellen eines Baums aus einem iterierbaren Element:
Einen Baum durchqueren:
quelle
Ich kann nicht anders, als zu bemerken, dass die meisten Antworten hier einen binären Suchbaum implementieren. Binärer Suchbaum! = Binärer Baum.
Ein binärer Suchbaum hat eine sehr spezifische Eigenschaft: Für jeden Knoten X ist der Schlüssel von X größer als der Schlüssel eines Nachkommen seines linken Kindes und kleiner als der Schlüssel eines Nachkommen seines rechten Kindes.
Ein Binärbaum unterwirft keine solche Einschränkung. Ein Binärbaum ist einfach eine Datenstruktur mit einem 'Schlüssel'-Element und zwei untergeordneten Elementen, z. B.' links 'und' rechts '.
Ein Baum ist ein noch allgemeinerer Fall eines Binärbaums, bei dem jeder Knoten eine beliebige Anzahl von untergeordneten Knoten haben kann. Normalerweise hat jeder Knoten ein untergeordnetes Element vom Typ Liste / Array.
Um die Frage des OP zu beantworten, füge ich jetzt eine vollständige Implementierung eines Binärbaums in Python hinzu. Die zugrunde liegende Datenstruktur, in der jeder BinaryTreeNode gespeichert ist, ist ein Wörterbuch, da sie optimale O (1) -Suchen bietet. Ich habe auch Travals mit der Tiefe und der Breite zuerst implementiert. Dies sind sehr häufige Operationen, die an Bäumen durchgeführt werden.
quelle
Sie müssen nicht zwei Klassen haben
quelle
Ein bisschen mehr "Pythonic"?
quelle
quelle
Eine auf
Node
Klassen basierende Klasse verbundener Knoten ist ein Standardansatz. Diese können schwer zu visualisieren sein.Betrachten Sie ein einfaches Wörterbuch, das aus einem Aufsatz über Python-Muster - Implementieren von Diagrammen motiviert ist :
Gegeben
Ein binärer Baum
Code
Erstellen Sie ein Wörterbuch mit eindeutigen Knoten:
Einzelheiten
find_all_paths()
).Baumbasierte Funktionen umfassen häufig die folgenden allgemeinen Operationen:
Versuchen Sie, alle diese Vorgänge zu implementieren. Hier zeigen wir eine dieser Funktionen - eine BFS-Durchquerung:
Beispiel
Dies ist ein Breitensuchalgorithmus (Level-Order) , der auf ein Diktat von Knoten und Kindern angewendet wird.
deque
, aber einqueue
oder einlist
Werk (letzteres ist ineffizient).Siehe auch dieses ausführliche Tutorial zu Bäumen.
Einblick
Etwas Großartiges an Durchläufen im Allgemeinen ist, dass wir den letztgenannten iterativen Ansatz für die Tiefensuche (DFS) leicht ändern können, indem wir einfach die Warteschlange durch einen Stapel ersetzen (auch bekannt als LIFO-Warteschlange) . Dies bedeutet einfach, dass wir uns von derselben Seite aus der Warteschlange entfernen, von der wir uns in die Warteschlange stellen. Mit DFS können wir jeden Zweig durchsuchen.
Wie? Da wir a verwenden
deque
, können wir einen Stapel emulieren, indem wirnode = q.popleft()
zunode = q.pop()
(rechts) wechseln . Das Ergebnis ist eine rechtsbegünstigte, vorbestellte DFS :['a', 'c', 'f', 'b', 'e', 'd']
.quelle
quelle
Diese Implementierung unterstützt Einfüge-, Such- und Löschvorgänge, ohne die Struktur des Baums zu zerstören. Dies ist kein Banlanced-Baum.
quelle
Ich weiß, dass bereits viele gute Lösungen veröffentlicht wurden, aber ich habe normalerweise einen anderen Ansatz für Binärbäume: Es ist besser, mit einer Knotenklasse zu arbeiten und sie direkt zu implementieren, aber wenn Sie viele Knoten haben, kann dies sehr speichergierig werden, also ich Schlagen Sie vor, eine Komplexitätsebene hinzuzufügen, die Knoten in einer Python-Liste zu speichern und anschließend ein Baumverhalten nur anhand der Liste zu simulieren.
Sie können weiterhin eine Knotenklasse definieren, um die Knoten im Baum bei Bedarf endgültig darzustellen. Wenn Sie sie jedoch in einer einfachen Form [Wert, links, rechts] in einer Liste aufbewahren, wird die Hälfte des Speichers oder weniger benötigt!
Hier ist ein kurzes Beispiel für eine binäre Suchbaumklasse, in der die Knoten in einem Array gespeichert sind. Es bietet grundlegende Funktionen wie Hinzufügen, Entfernen, Suchen ...
Ich habe ein übergeordnetes Attribut hinzugefügt, damit Sie jeden Knoten entfernen und die BST-Struktur beibehalten können.
Entschuldigen Sie die Lesbarkeit, insbesondere die Funktion "Entfernen". Grundsätzlich entfernen wir beim Entfernen eines Knotens das Baumarray und ersetzen es durch das letzte Element (außer wenn wir den letzten Knoten entfernen wollten). Um die BST-Struktur beizubehalten, wird der entfernte Knoten durch das Maximum seiner linken Kinder oder das Minimum seiner rechten Kinder ersetzt, und einige Operationen müssen ausgeführt werden, um die Indizes gültig zu halten, aber es ist schnell genug.
Ich habe diese Technik für fortgeschrittenere Dinge verwendet, um einige Wörterbücher mit großen Wörtern mit einem internen Radix-Versuch zu erstellen, und ich konnte den Speicherverbrauch durch 7-8 teilen (ein Beispiel finden Sie hier: https://gist.github.com/fbparis / b3ddd5673b603b42c880974b23db7cda )
quelle
Eine gute Implementierung des binären Suchbaums von hier :
quelle
Ich möchte eine Variation der Methode von @ apadana zeigen, die bei einer beträchtlichen Anzahl von Knoten nützlicher ist:
quelle
quelle
Binärer Baum in Python
quelle
Hier ist eine einfache Lösung, mit der ein Binärbaum mithilfe eines rekursiven Ansatzes erstellt werden kann, um den Baum in der Reihenfolge anzuzeigen, in der die Durchquerung im folgenden Code verwendet wurde.
Code aus: Binärbaum in Python
quelle