Lecture Notes on 04 Apr 2022 * Deleting nodes in a binary search tree - leaf node - node with one child - node with two children * Balancing Trees * Balance Factor = Height of left sub-tree - Height of right sub-tree * In a balanced tree the balance factor of every node is either -1, 0, 1 * AVL Trees https://www.cs.usfca.edu/~galles/visualization/AVLtree.html * AVL Trees Notes https://www.cs.utexas.edu/users/mitra/csSpring2022/cs313/notes/AVL_Trees.pdf * Notes on Heaps https://www.cs.utexas.edu/users/mitra/csSpring2022/cs313/notes/Heaps.pdf * Code for the Tree data structure class Node (object): def __init__ (self, data): self.data = data self.lc = None self.rc = None # self.parent = None # self.visited = False def __str__ (self): s = '' return s class Tree (object): def __init__ (self): self.root = None # self.size = 0 # insert data into the tree def insert_node (self, data): new_node = Node (data) if (self.root == None): self.root = new_node return else: current = self.root parent = self.root while (current != None): parent = current if (data < current.data): current = current.lc else: current = current.rc if (data < parent.data): parent.lc = new_node else: parent.rc = new_node # search for a node with given data def search_node (self, data): current = self.root while (current != None) and (current.data != data): if (data < current.data): current = current.lc else: current = current.rc return current # inorder traversal - left, center, right def in_order (self, aNode): if (aNode != None): self.in_order (aNode.lc) print (aNode.data) self.in_order (aNode.rc) # preorder traversal - center, left, right def pre_order (self, aNode): if (aNode != None): print (aNode.data) self.pre_order (aNode.lc) self.pre_order (aNode.rc) # postorder traversal - left, right, center def post_order (self, aNode): if (aNode != None): self.post_order (aNode.lc) self.post_order (aNode.rc) print (aNode.data) # Find the node with the smallest value def min_node (self): current = self.root parent = self.root while (current != None): parent = current current = current.lc return parent # Find the node with the largest value def max_node (self): current = self.root parent = current while (current != None): parent = current current = current.rc return parent # delete a node with a given key def delete_node (self, data): delete_node = self.root parent = self.root is_left = False # if empty tree if (delete_node == None): return None # find the node containing the data while (delete_node != None) and (delete_node.data != data): parent = delete_node if (data < delete_node.data): delete_node = delete_node.lc is_left = True else: delete_node = delete_node.rc is_left = False # if node not found if (delete_node == None): return None # check if the delete node is a leaf node if (delete_node.lc == None) and (delete_node.rc == None): if (delete_node == self.root): self.root = None elif (is_left): parent.lc = None else: parent.rc = None # check if the delete node is a node with only a left child elif (delete_node.rc == None): if (delete_node == self.root): self.root = delete_node.lc elif (is_left): parent.lc = delete_node.lc else: parent.rc = delete_node.lc # Delete node is a node with only right child elif (delete_node.lc == None): if (delete_node == self.root): self.root = delete_node.rc elif (is_left): parent.lc = delete_node.rc else: parent.rc = delete_node.rc # Delete node is a node with both left and right child else: # Find delete node's successor and successor's parent nodes successor = delete_node.rc successor_parent = delete_node while (successor.lc != None): successor_parent = successor successor = successor.lc # Successor node right child of delete node if (delete_node == self.root): self.root = successor elif (is_left): parent.lc = successor else: parent.rc = successor # Connect delete node's left child to be successor's left child successor.lc = delete_node.lc # Successor node left descendant of delete node if (successor != delete_node.rc): successor_parent.lc = successor.rc successor.rc = delete_node.rc return delete_node