Binary Search Tree (BST)

Context: FIT1008_MOC · a Binary Tree with an ordering Invariant · an alternative implementation of a Dictionary (ADT) · cost depends on balance

Quick Revision

  • 🎯 Objective: left < node < right invariant ➔ search becomes halving, cost — binary search made dynamic.
  • 📦 Core Components: search ➔ go left/right | insert ➔ return-and-relink | delete ➔ three cases via in-order successor.
  • ⚡ Key Constraint: balanced, degenerate ➔ good at search and insert/delete, and ordered (unlike a hash table).

📝 Core

1. The BST (Ordering Invariant)

  • Invariant ➔ for every node, left-subtree keys less, right-subtree keys greater (keys unique).
  • Search halving ➔ go left/right by comparison ➔ cost depth; key/item kept separate.
  • Balance dependency ➔ balanced , sorted-insert stick ; self-balancing = AVL · 2-3 · left-leaning red-black (FIT2004 W10) · 2-3-4.
  • Mechanism ➔ recurse left/right by key; at the empty leaf position, create the node.
  • Critical return ➔ return current and re-assign the link on the way back (current.left = insert_aux(...), self.root = insert_aux(...)).
  • Duplicate ➔ raise, or current.item = item for insert-or-update (__setitem__).
  • Unique insertion point (applied P3) ➔ for with predecessor and successor , one is an ancestor of the other — otherwise their split ancestor gives with , a key strictly between and or and . above ⟹ has a left child and has no right child ( would give ) ⟹ becomes ‘s right child; above ⟹ the mirror, becomes ‘s left child. Exactly one holds ⟹ one legal slot.

3. Delete (Three Cases via Successor)

  • Leaf ➔ null the parent link · one child ➔ bypass · two children ➔ replace key/item with the in-order successor (one step right, then all the way left), then delete it — the successor has no left child, so its removal is the easy case, and the next-largest key preserves left<root<right.
  • FIT2004 framing ➔ delete only ever removes a leaf: swap the key with its in-order predecessor (biggest in left subtree) or successor (smallest in right subtree) first — the question names which, so drill both; the choice can change the resulting tree and which rebalancing fires in an AVL Tree.
  • Why the successor has no left child (applied P2, proof by contradiction) ➔ (a) is in ‘s right subtree: a split ancestor would give ; above would put ‘s right child at · (b) a left child of lies in ‘s right subtree ⟹ . Both contradict ” is the smallest key “.

4. Building the tree: insertions into an empty BST (FIT2004)

  • Worst case ➔ feed keys already sorted ➔ every key descends the growing right spine, the -th insertion walking nodes ⟹ (Arithmetic Series).
  • Best case ➔ an arrival order that keeps the tree balanced ⟹ each insertion .
  • Per-op worst × is only an UPPER bound ➔ “each insertion is , so of them are ” is valid but does not establish ; tightness needs a witness input on which the worst cases genuinely co-occur, which sorted input supplies. This is the degenerate-chain failure that motivates AVL/red-black balancing.

5. Minimal-Height Build From Keys (FIT2004 applied P7)

  • Algorithm ➔ sort, then make the median the root and recurse on the two halves ➔ code below; total , dominated by the sort.
  • Height ➔ each half has keys ⟹ , ; telescoping , set ⟹ (Solving Recurrences (Telescoping)).
  • is optimal ➔ reduction to sorting: building any BST in , then an in-order traversal, would sort in — impossible in the comparison model (Sorting Problem).

⚙️ Core Implementation

🔹 Search + Insert

🔹 Iterating a tree — explicit-stack preorder

🔹 Minimal-height build (applied P7)

⚖️ Core Decision Matrix

Variant / Strategysearchinsert / deleteOrdered?Note
BST (balanced)yesgood at both; range/successor
BST (degenerate)yessorted input → LinkList stick
sorted array shiftyesfast search, slow insert
sorted linked list positionedyesfast insert, slow search
Hash Table expected expectednofastest, no order/range

When It Flips: a BST is good at both search and insert/delete, unlike a sorted array/linked list (each wins one); vs a hash table it is slower per op but traversable in key order with range/predecessor/successor queries. Correctness = ops maintain the BST invariant (BST in ⟹ BST out).

📊 Exam Execution Trace

Manual Execution Trace

Insert 5, 3, 8, 4, 7, then delete 8 (one child 7):

Step / StateTrigger OpTree (parenthesised) Payload
0 (Init)init(empty)
1insert 55
2insert 35(3,_)
3insert 85(3, 8)
4insert 45(3(_,4), 8)
5insert 75(3(_,4), 8(7,_))
6delete 8one child → bypass: 5(3(_,4), 7)

✍️ Practice

🧠 Active Recall