Question bank — Binary Search Tree (BST) — BST property, insert, search, delete (3 cases)
Every reveal below uses the Question ::: Answer format: read up to the :::, decide, then check.
Symbols and reference snippets used on this page
Before the traps, here is every symbol and every code fragment this page leans on, defined once so the page stands alone.
Three pictures anchor the traps that follow — glance at them now, they'll be referenced by name.



True or false — justify
The verdict alone is worthless here. Say why before revealing.
If a node's key is greater than its left child and less than its right child, the whole tree is a valid BST
6 passes its parent's check yet is smaller than the ancestor 10 while living in 10's right subtree. Validity needs a range that tightens as you descend.An in-order traversal of any binary tree gives keys in sorted order
The same set of keys always produces the same BST shape
Searching a BST is always
In a BST, the smallest key is always the leftmost node
find_min exploits exactly this. Symmetrically the largest is the rightmost node.Deleting a node with two children removes exactly the two subtrees it pointed to
Inserting a key that already exists in the BST adds a second copy as a new leaf
insert snippet above reaches v == root.key and just returns root, ignoring it. Handling duplicates is a design choice; the plain BST as written simply drops them.A newly inserted key can become an internal (non-leaf) node
None child and attaches the key there. New keys are always leaves, which is exactly why no existing pointers break.The in-order predecessor works just as well as the successor for two-child deletion
Every subtree of a valid BST is itself a valid BST
Spot the error
Find what's broken and say why it breaks.
"To search, compare with the root; if not equal, search BOTH children to be safe."
"For Case 3 delete (two children), I'll copy the predecessor's value but then delete the successor node."
"is_bst only needs to check left.key < key < right.key at each node."
"After deleting a leaf I set the node itself to None inside the function."
None doesn't update the parent's pointer. The removal must happen by returning the new subtree (return None) so the parent's root.left/root.right is reassigned."The in-order successor might have a left child I need to reattach."
"To delete key v, I recurse into the left subtree whenever v <= root.key."
<= sends you left even when v == root.key, so you'd walk past the node you're trying to delete and never find it. Equality must trigger the delete logic, not a direction."Inserting always keeps the tree balanced because we descend one path."
Why questions
The reasoning IS the answer here.
Why does a single comparison at a node let us discard a whole subtree?
Why is delete for a two-child node (Case 3) reduced to deleting a node with ≤ 1 child?
Why does return root.right elegantly handle both the leaf case (Case 1) and the one-child-no-left case (Case 2)?
root.right is None, so the parent's pointer becomes None (leaf removed). If it has only a right child, root.right is that child, which gets spliced up. One line, two cases.Why is in-order traversal the right sanity check for BST validity?
Why do we prefer a BST over a plain Binary Search on Sorted Array?
Why does inserting sorted keys produce the worst case?
Why must the validation range tighten as we recurse rather than stay fixed?
high = k; going right sets low = k. Fixed bounds would miss these inherited constraints.Edge cases
Boundaries that break naive assumptions.
Search or delete on an empty tree (root is None)
None (not found) and delete returns None (nothing to remove) immediately. The base case if node is None handles this before any comparison — no special-casing needed.Deleting a node with only a left child (no right child)
if root.right is None: return root.left, splicing the lone left child straight up to the parent. The mirror of the no-left case.Deleting a node with only a right child (no left child)
if root.left is None: return root.right — the same line that also covers a leaf (where root.right is None). Both one-child directions are explicitly caught.Deleting the root when it's the only node
root.left is None so return root.right returns None, and the caller reassigns the tree to None. The whole tree correctly becomes empty.Deleting the root when it has two children
A tree consisting of a single all-left or all-right chain
Duplicate insertion in the standard implementation
v == root.key branch does nothing, so the tree is unchanged and the key count stays the same. Any duplicate policy (count field, always-right, etc.) is an intentional extension, not default behaviour.The in-order successor when the deleted node's right child has no left subtree
find_min stops immediately and we splice around it — still Case 1 or 2.Recall Fast self-test
Cover the answers and reproduce the reason (not just the verdict) for: (a) the local-child validation trap, (b) why successor deletion never recurses into another two-child case, (c) why sorted insertion is worst-case. Reason for (a) ::: local checks miss ancestor bounds; need a shrinking range. Reason for (b) ::: successor is leftmost of right subtree → no left child → Case 1 or 2. Reason for (c) ::: each key attaches right, forming a height stick.
Related depth: Recursion on Trees, Tree Height vs Depth, Heap vs BST, Binary Tree — terminology & traversals.