Previous Lecture | Lecture 19 | Next Lecture |
Lecture 19, Tue 06/06
Binary Search Trees cont.
Recorded Lecture: 6_6_23
BST Deletion Implementation
# BinarySearchTree.py (continuing on from last lecture)
def delete(self,key):
if self.size > 1:
nodeToRemove = self._get(key,self.root)
if nodeToRemove:
self.remove(nodeToRemove) # remove modifies the tree
self.size = self.size-1
else:
raise KeyError('Error, key not in tree')
elif self.size == 1 and self.root.key == key:
self.root = None
self.size = self.size - 1
else:
raise KeyError('Error, key not in tree')
# Used to remove the node and account for BST deletion cases
def remove(self,currentNode):
# Case 1: Node to remove is leaf
if currentNode.isLeaf():
if currentNode == currentNode.parent.leftChild:
currentNode.parent.leftChild = None
else:
currentNode.parent.rightChild = None
# Case 3: Node to remove has both children
elif currentNode.hasBothChildren():
# Need to find the successor, remove successor, and replace
# currentNode with successor's data / payload
succ = currentNode.findSuccessor()
succ.spliceOut()
currentNode.key = succ.key
currentNode.payload = succ.payload
# Case 2: Node to remove has one child
else:
# Node has leftChild
if currentNode.hasLeftChild():
if currentNode.isLeftChild():
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.leftChild
elif currentNode.isRightChild():
currentNode.leftChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.leftChild
else: # currentNode is the Root
currentNode.replaceNodeData(currentNode.leftChild.key,
currentNode.leftChild.payload,
currentNode.leftChild.leftChild,
currentNode.leftChild.rightChild)
# Node has rightChild
else:
if currentNode.isLeftChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.leftChild = currentNode.rightChild
elif currentNode.isRightChild():
currentNode.rightChild.parent = currentNode.parent
currentNode.parent.rightChild = currentNode.rightChild
else:
currentNode.replaceNodeData(currentNode.rightChild.key,
currentNode.rightChild.payload,
currentNode.rightChild.leftChild,
currentNode.rightChild.rightChild)
# Used for pytesting
def inOrder(self, node):
ret = ""
if node != None:
ret += self.inOrder(node.leftChild)
ret += str(node.key) + " "
ret += self.inOrder(node.rightChild)
return ret
# TreeNode.py (continuing on from last lecture)
def findSuccessor(self):
succ = None
# Check if node has a right subtree...
if self.hasRightChild():
# traverse through left children (min)
succ = self.rightChild.findMin()
return succ
# Find minimum value in a subtree by walking down the left children
def findMin(self):
current = self
while current.hasLeftChild():
current = current.leftChild
return current
# Used to delete the successor
def spliceOut(self):
# Case 1:
# If node to be removed is a leaf, set parent's left or right
# child references to None
if self.isLeaf():
if self.isLeftChild():
self.parent.leftChild = None
else:
self.parent.rightChild = None
# Case 2:
# Not a leaf node. Should only have a right child for BST
# removal
elif self.hasAnyChildren():
if self.hasRightChild():
if self.isLeftChild():
self.parent.leftChild = self.rightChild
else:
self.parent.rightChild = self.rightChild
self.rightChild.parent = self.parent
# Note: This code only goes through the findSuccessor and spliceOut functionality necessary
# for BST maintenance. There are more general cases that the textbook covers that you should
# read through and understand
# pytests
def test_deleteSingleRoot():
BST = BinarySearchTree()
BST.put(10, "ten")
assert BST.inOrder(BST.root) == "10 "
BST.delete(10)
assert BST.size == 0
assert BST.root == None
def test_deleteRootOneChild():
BST = BinarySearchTree()
BST.put(10, "ten")
BST.put(5, "five")
assert BST.inOrder(BST.root) == "5 10 "
BST.delete(10)
assert BST.inOrder(BST.root) == "5 "
assert BST.root.key == 5
def test_deleteLeaf():
BST = BinarySearchTree()
BST.put(10, "ten")
BST.put(15, "fifteen")
BST.put(5, "five")
BST.put(2, "two")
assert BST.inOrder(BST.root) == "2 5 10 15 "
BST.delete(15)
assert BST.inOrder(BST.root) == "2 5 10 "
def test_deleteNodeOneChild():
BST = BinarySearchTree()
BST.put(10, "ten")
BST.put(15, "fifteen")
BST.put(5, "five")
BST.put(2, "two")
assert BST.root.leftChild.key == 5
BST.delete(5)
assert BST.inOrder(BST.root) == "2 10 15 "
assert BST.root.leftChild.key == 2
assert BST.root.leftChild.parent.key == 10
def test_deleteRootWithTwoChildren():
BST = BinarySearchTree()
BST.put(10, "ten")
BST.put(15, "fifteen")
BST.put(5, "five")
BST.put(3, "three")
BST.put(7, "seven")
BST.put(12, "twelve")
BST.put(17, "seventeen")
assert BST.inOrder(BST.root) == "3 5 7 10 12 15 17 "
BST.delete(10)
assert BST.inOrder(BST.root) == "3 5 7 12 15 17 "
def test_deleteNodeWithTwoChildren():
BST = BinarySearchTree()
BST.put(10, "ten")
BST.put(15, "fifteen")
BST.put(5, "five")
BST.put(3, "three")
BST.put(7, "seven")
BST.put(12, "twelve")
BST.put(17, "seventeen")
BST.delete(15)
assert BST.inOrder(BST.root) == "3 5 7 10 12 17 "
BST.delete(5)
assert BST.inOrder(BST.root) == "3 7 10 12 17 "