This homework implements a full Binary Search Tree (BST) in Python, includingDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/tutosrive/ed/llms.txt
Use this file to discover all available pages before exploring further.
insert, search, and delete operations. The deletion logic covers every structural case a node can be in: having no children (leaf), one child, or two children — as well as the special case of deleting the root itself. All six deletion scenarios are validated against a 20-value dataset to confirm the BST invariant is preserved after every operation.
Full BST Implementation
The implementation uses two classes:Node (holding a value plus left, right, and parent pointers) and BST (managing insertion, search, deletion, and traversal). The changeNodePosition helper centralises all parent-pointer rewiring, keeping the deletion logic clean and reusable.
bst.py
Test Dataset
The 20 insertion values are chosen to produce a balanced-looking BST with nodes at every structural position — leaves, single-child nodes, and multi-child nodes including the root.test_values.py
Deletion Test Cases
Each deletion targets a different structural scenario. The BST invariant — that an inorder traversal always produces sorted output — must hold after every removal.Delete leaf node 5
Node
5 has no children. _delete matches Case 1 and calls changeNodePosition(node, None), which simply sets the parent’s (10) left pointer to None. The node is detached with no further rewiring needed.delete_leaf.py
Delete node with one child (35)
Node
35 has only a right child (33 is its left child after the previous deletion leaves 33 as the single child — specifically, 35 holds left child 33 with no right child). _delete matches Case 3 and calls changeNodePosition(node_35, node_35.left), promoting 33 directly into 35’s position under parent 40.delete_one_child.py
Delete node with two children (30)
Node
30 has both a left subtree (rooted at 20) and a right subtree (rooted at 40). _delete matches Case 2. _getPredecessor(30) walks left to 20, then follows right pointers as far as possible, landing on 25 — the inorder predecessor.Because 25 is not a direct child of 30, the algorithm first detaches 25 from its position (replacing it with its own left child, if any), then rewires 25 to take over 30’s left and right subtrees via changeNodePosition.delete_two_children.py
Delete the root (50)
Node
50 is the root (parent is None) and has two children. _delete applies Case 2 identically — but changeNodePosition detects node_to_replace.parent is None and assigns self.root = new_subtree_root instead of updating a parent pointer. The inorder predecessor of 50 (node 45) becomes the new root.delete_root.py
Delete another two-children node (70)
Node
70 has left child 60 and right child 80. Its inorder predecessor is 65 (rightmost in its left subtree). 65 is detached from under 60, then promoted into 70’s position, inheriting both 60 and 80 as children.delete_70.py
Running the Tests
The complete test script builds the tree, prints the initial structure, then performs all six deletions in sequence. After each deletion both a visual tree print and an inorder traversal confirm structural correctness.run_tests.py
After each deletion the BST invariant must be preserved — an inorder traversal (left → root → right) must still yield all remaining values in strictly ascending order. This is the primary correctness check for any BST deletion implementation.