BST-Einfügen und -Suchen
Implementieren Sie rekursives und iteratives Einfügen und Suchen, verfolgen Sie den Pfad durch den Baum für verschiedene Schlüssel und analysieren Sie die Worst-Case-Komplexität unbalancierter Bäume.
BST-Einfügen und -Suchen ist eine kostenlose Coding Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Coding Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Die BST-Eigenschaft
Ein Binary Search Tree erfüllt eine Invariante: Für jeden Knoten sind alle Werte in seinem linken Teilbaum strikt kleiner als der Wert des Knotens, und alle Werte in seinem rechten Teilbaum strikt größer. Diese Ordnungseigenschaft, die für den gesamten Teilbaum und nicht nur für die unmittelbaren Kinder gilt, ermöglicht Suchen, Einfügen und Löschen in O(log n) bei ausgeglichenen Bäumen und unterscheidet einen BST von einem allgemeinen Binärbaum.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
# Valid BST:
# 4
# / \
# 2 6
# / \ / \
# 1 3 5 7
# For node 4: left subtree {1,2,3} < 4 < right subtree {5,6,7}
# This holds recursively for EVERY node in the tree.
print('BST property: left < node < right at every level')Rekursive BST-Suche
Die Suche in einem BST funktioniert wie eine binäre Suche: Vergleichen Sie das Ziel mit dem Wert des aktuellen Knotens und rufen Sie die passende Teilbaumrekursion auf. Wenn das Ziel dem aktuellen Wert entspricht, geben Sie den Knoten zurück. Wenn das Ziel kleiner ist, gehen Sie nach links, bei einem größeren Ziel nach rechts. Geben Sie null zurück, wenn Sie einen leeren Knoten erreichen. Die Laufzeit beträgt O(h) – O(log n) bei ausgeglichenen und O(n) bei schiefen Bäumen.
def search_bst(root, val):
if not root:
return None # not found
if root.val == val:
return root # found
if val < root.val:
return search_bst(root.left, val)
else:
return search_bst(root.right, val)
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
result = search_bst(root, 2)
print(result.val if result else 'Not found') # 2
result = search_bst(root, 5)
print(result.val if result else 'Not found') # Not foundIterative BST-Suche
Die iterative Suche vermeidet den Overhead des Aufrufstapels und wird in produktivem Code bevorzugt. Verwenden Sie einen Zeiger curr, der den Baum durchläuft und je nach Vergleich nach links oder rechts weitergeht. Dies ist eine einfache while-Schleife mit drei Fällen: null (nicht gefunden), Übereinstimmung (gefunden) oder Anpassung der Richtung. Die iterative Suche hat ebenfalls O(h) Laufzeit, benötigt aber O(1) Speicherplatz statt O(h) bei der rekursiven Variante.
def search_bst_iterative(root, val):
curr = root
while curr:
if val == curr.val:
return curr
elif val < curr.val:
curr = curr.left
else:
curr = curr.right
return None # not found
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
node = search_bst_iterative(root, 3)
print(node.val if node else 'Not found') # 3
print(search_bst_iterative(root, 9)) # NoneRekursives Einfügen in einen BST
Beim Einfügen in einen BST wird die richtige Position ermittelt, indem dieselben Entscheidungen für links oder rechts wie bei der Suche getroffen werden. Anschließend wird an der ersten erreichten Position null ein neuer Knoten eingefügt. Der rekursive Ansatz gibt die möglicherweise neue Wurzel jedes Teilbaums zurück: Wenn der aktuelle Knoten null ist, geben Sie einen neuen TreeNode zurück; andernfalls aktualisieren Sie root.left oder root.right mit dem Ergebnis des rekursiven Aufrufs. Dieses Muster ist übersichtlich und in Interviewlösungen weit verbreitet.
def insert_bst(root, val):
if not root:
return TreeNode(val) # create new node here
if val < root.val:
root.left = insert_bst(root.left, val)
elif val > root.val:
root.right = insert_bst(root.right, val)
# val == root.val: duplicate, do nothing (or handle as needed)
return root
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root = insert_bst(root, 1)
root = insert_bst(root, 5)
# Tree is now: 4, left=2(left=1), right=7(left=5)
print(root.right.left.val) # 5Iteratives Einfügen in einen BST
Beim iterativen Einfügen wird mit einem Zeiger parent der letzte Nicht-Null-Knoten vor der Einfügeposition verfolgt. Durchlaufen Sie den Baum wie bei der Suche und speichern Sie dabei den Elternknoten sowie die zuletzt eingeschlagene Richtung. Wenn Sie null erreichen, hängen Sie den neuen Knoten an der entsprechenden Seite des Elternknotens ein. Behandeln Sie den Sonderfall eines leeren Baums (die Wurzel ist null) immer separat.
def insert_bst_iterative(root, val):
new_node = TreeNode(val)
if not root:
return new_node
curr = root
while True:
if val < curr.val:
if curr.left is None:
curr.left = new_node
break
curr = curr.left
else: # val > curr.val
if curr.right is None:
curr.right = new_node
break
curr = curr.right
return root
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root = insert_bst_iterative(root, 3)
print(root.left.right.val) # 3BST im schlimmsten Fall: Schiefe Bäume
Wenn Sie eine sortierte Folge in einen BST einfügen, entsteht ein schiefer Baum, der zu einer verketteten Liste degeneriert. Suche, Einfügen und Löschen haben dann alle eine Laufzeit von O(n). Deshalb gibt es ausgeglichene BSTs (AVL-Bäume, Red-Black-Bäume). Erwähnen Sie in Interviews bei Fragen zur Komplexität eines BST immer diesen Worst Case – die Aussage „durchschnittlich O(log n), im schlechtesten Fall O(n) bei unausgeglichenen Bäumen“ zeigt ein gutes Verständnis.
# Inserting 1, 2, 3, 4, 5 into a BST:
# 1
# \
# 2
# \
# 3
# \
# 4
# \
# 5
# This is a right-skewed tree: search is O(n) not O(log n)
root = None
for val in [1, 2, 3, 4, 5]:
root = insert_bst(root, val)
# Verify the skew
node = root
depth = 0
while node:
depth += 1
node = node.right
print(f'Height: {depth}') # 5 = O(n), not O(log n)Minimum und Maximum finden
In einem BST befindet sich der Minimalwert immer im am weitesten links liegenden Knoten (gehen Sie so lange nach links, bis Sie null erreichen), der Maximalwert entsprechend im am weitesten rechts liegenden Knoten. Diese Operationen mit O(h) Laufzeit werden häufig als Teilroutinen beim Löschen aus einem BST (zum Finden des Inorder-Nachfolgers) und bei Bereichsabfragen verwendet. Wenn Sie diese Hilfsverfahren sicher beherrschen, sparen Sie in Interviews Zeit.
def find_min(root):
while root.left:
root = root.left
return root
def find_max(root):
while root.right:
root = root.right
return root
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(7)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
root.right.right = TreeNode(9)
print(find_min(root).val) # 1
print(find_max(root).val) # 9Inorder-Nachfolger und -Vorgänger
Der Inorder-Nachfolger eines Knotens ist der Knoten mit dem kleinsten Wert, der größer als der Wert des gegebenen Knotens ist. Wenn der Knoten einen rechten Teilbaum besitzt, ist der Nachfolger find_min(node.right). Wenn er keinen rechten Teilbaum besitzt, ist der Nachfolger der niedrigste Vorfahr, in dessen linkem Teilbaum sich der gegebene Knoten befindet. Dieses Verständnis ist für das Löschen aus einem BST und für BST-Iterator-Probleme entscheidend.
def inorder_successor(root, p):
successor = None
while root:
if p.val < root.val:
successor = root # possible successor
root = root.left
else:
root = root.right
return successor
def inorder_predecessor(root, p):
predecessor = None
while root:
if p.val > root.val:
predecessor = root # possible predecessor
root = root.right
else:
root = root.left
return predecessor
root = TreeNode(4)
root.left = TreeNode(2)
root.right = TreeNode(6)
root.left.left = TreeNode(1)
root.left.right = TreeNode(3)
p = root.left # node with val=2
print(inorder_successor(root, p).val) # 3
print(inorder_predecessor(root, p).val) # 1Analyse der BST-Suchkomplexität
Die Leistung eines BST hängt vollständig von der Baumhöhe ab. Bei einem ausgeglichenen BST mit n Knoten beträgt die Höhe O(log n), wodurch Suche, Einfügen und Löschen jeweils O(log n) benötigen. Bei einem schiefen BST beträgt die Höhe O(n), sodass alle Operationen O(n) benötigen. Python verfügt im Gegensatz zu Javas TreeMap nicht über einen integrierten ausgeglichenen BST. Sie können daher entweder selbst einen AVL- oder Red-Black-Baum implementieren, sortedcontainers.SortedList verwenden oder für Anwendungsfälle mit Prioritätswarteschlangen auf einen Heap zurückgreifen.
# Python's BST alternatives:
# 1. heapq - min/max heap, O(log n) push/pop
# 2. sortedcontainers.SortedList (third-party, often allowed)
# 3. Manual AVL or Red-Black (rarely required in interviews)
# When interviews say 'use a BST':
# - LeetCode: implement TreeNode-based solution
# - Real interview: mention sortedcontainers or Java TreeMap equivalent
# - O(log n) operations matter when you need ordered access
# For pure insert/lookup without ordering: use dict (O(1) average)
print('Use heap for priority, dict for lookup, BST for ordered range')Einfügen in einen BST: Sonderfälle
Überprüfen Sie beim Einfügen immer, ob folgende Fälle behandelt werden: leerer Baum (den neuen Knoten als Wurzel zurückgeben), doppelte Werte (festlegen, ob sie ignoriert, links oder rechts eingefügt werden, und diese Entscheidung konsequent umsetzen) sowie sehr große oder kleine Werte. Geben Sie in Interviews vor dem Programmieren an, welche Annahme Sie zu Duplikaten treffen. In LeetCode-Aufgaben gilt üblicherweise, dass alle Werte verschieden sind, sofern nichts anderes angegeben ist.
def insert_bst_no_duplicates(root, val):
if not root:
return TreeNode(val)
if val < root.val:
root.left = insert_bst_no_duplicates(root.left, val)
elif val > root.val:
root.right = insert_bst_no_duplicates(root.right, val)
# else: val == root.val -> duplicate, skip
return root
# Test all edge cases:
root = None
root = insert_bst_no_duplicates(root, 5) # empty tree
root = insert_bst_no_duplicates(root, 5) # duplicate
root = insert_bst_no_duplicates(root, 3)
root = insert_bst_no_duplicates(root, 7)
print(root.val, root.left.val, root.right.val) # 5 3 7BST aus einem sortierten Array
Das Erstellen eines höhenbalancierten BST aus einem sortierten Array (LeetCode #108) verwendet Teile und Herrsche: Das mittlere Element wird zur Wurzel, die linke Hälfte zum linken Teilbaum und die rechte Hälfte zum rechten Teilbaum. Dadurch wird ein ausgeglichener Baum mit der Höhe O(log n) garantiert. Die Laufzeit beträgt O(n), da jedes Element genau einmal verarbeitet wird.
def sorted_array_to_bst(nums):
if not nums:
return None
mid = len(nums) // 2
root = TreeNode(nums[mid])
root.left = sorted_array_to_bst(nums[:mid])
root.right = sorted_array_to_bst(nums[mid+1:])
return root
nums = [-10, -3, 0, 5, 9]
root = sorted_array_to_bst(nums)
print(root.val) # 0 (middle element)
print(root.left.val) # -3
print(root.right.val) # 9Kurze Überprüfung
Testen Sie Ihr Verständnis der Konzepte aus Data Structures & Algorithms — Coding Interview Prep aus dieser Lektion.
Zusammenfassung der Lektion
In dieser Lektion haben Sie Folgendes gelernt: die BST-Eigenschaft (linker Teilbaum strikt kleiner, rechter Teilbaum strikt größer), Suche und Einfügen sowohl rekursiv als auch iterativ mit einer Laufzeit von O(h) sowie schiefe Bäume im schlimmsten Fall, bei denen die Höhe n entspricht. Als Nächstes behandeln wir das Löschen aus einem BST und seine drei Fälle.
Häufig gestellte Fragen
Ist die Lektion „BST-Einfügen und -Suchen“ kostenlos?
Ja — der vollständige Text von „BST-Einfügen und -Suchen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Coding Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „BST-Einfügen und -Suchen“?
Implementieren Sie rekursives und iteratives Einfügen und Suchen, verfolgen Sie den Pfad durch den Baum für verschiedene Schlüssel und analysieren Sie die Worst-Case-Komplexität unbalancierter Bäume. Du übst Coding Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Coding Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. Coding Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „BST-Einfügen und -Suchen“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Coding Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede Coding Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- BST-Einfügen und -Suchen
- BST-Löschen: drei Fälle
- BST und In-Order-Eigenschaften validieren
- K-kleinstes Element, Bereichssumme und BST zu sortiertem Array