Sorted List (ADT)
Context: FIT1008_MOC · a List (ADT) under a sort Invariant · backbone clustering its SortedArrayList implementation · the motivation for a balanced Binary Tree
Quick Revision
- 🎯 Objective: list kept in value order ➔ fast search, but user loses position choice (append/insert → add).
- 📦 Core Components: Contract ➔
add+ fasterindex| SortedArrayList ➔ Binary Search search, shift-on-insert.- ⚡ Key Constraint: array gives search but insert (shift) ➔ for both needs a balanced Binary Tree.
📝 Core
1. Sorted List Contract (Sort Invariant)
- Sort invariant ➔ a List (ADT) whose elements stay in increasing order (Invariant).
- Op remap ➔
append/insert/__setitem__meaningless ➔ replaced by a singleadd. - Not a List subclass ➔ would break the
Listcontract (insert(i,x)demands arbitrary placement) ➔ shared fields ≠ “is-a”.
2. SortedArrayList (Array-Backed)
- Storage substrate ➔ fixed Array (Data Structure) +
length, elements increasing. - Distinctive ops ➔
indexvia Binary Search () |add= find slot + shift . - Shift dominates ➔
addis unless the item belongs at the very end.
⚙️ Core Implementation
🔹 SortedArrayList — binary-search index, shift-on-add
index(binary search) +adddef index(self, item): # Binary Search: O(log n) low, high = 0, len(self) - 1 while low <= high: mid = low + (high - low) // 2 if self.array[mid] == item: return mid elif self.array[mid] < item: low = mid + 1 else: high = mid - 1 raise ValueError("item not in list") def add(self, item): # find slot (O(log n)) + make space (O(n)) i = self.__index_to_add(item) # binary-search insertion point self.__make_space(i) # shift right (+ resize if full) self.array[i] = item; self.length += 1💡 Common Mistake: search win is masked in
add➔ the shift dominates;addis only when the item lands at the end.
⚖️ Core Decision Matrix
| Variant / Strategy | index (search) | add | Ordered iteration | Cache / Note |
|---|---|---|---|---|
| SortedArrayList | (Binary Search) | find + shift | random access enables binary search | |
| sorted linked list | (no random access) | find + splice | fast splice, can’t binary-search | |
| balanced BST | only one for both |
When It Flips: the array can't make
addcheap ( find but shift); the sorted linked list is the inverse (slow find, fast splice). Only a balanced Binary Tree links a node in place ➔ insert and search.
📊 Exam Execution Trace
Manual Execution Trace
add(15) into [4, 8, 23, 42]:
| Step / State | Trigger Op | Action | Array Payload |
|---|---|---|---|
| 0 (Init) | start | add 15 | [4, 8, 23, 42] |
| 1 | binary-search slot | converge → index 2 | (between 8 and 23) |
| 2 | make-space (shift) | 23,42 moved () | [4, 8, _, 23, 42] |
| 3 | place | length += 1 | [4, 8, 15, 23, 42] |
Applied Exercise
Problem: Show why add is despite an search.
Derivation Proof / Hand-Calculation Walkthrough:
Final Extracted Output: add in general — the contiguous-block shift, not the search, is the bottleneck.
🧠 Active Recall
Why is a SortedList modelled as a separate abstract class rather than a subclass of List?
- Hint: Recognise the broken Liskov substitution.
Answer
- Short answer: The sort invariant makes
append/insert/__setitem__meaningless ➔ a newaddis required.- Why: Contract break ➔ a subclass “implementing”
insertby ignoring/ raising violates theListcontract; shared fields ≠ “is-a”.
Binary search finds a slot in , yet
addis — explain, and name the structure that fixes it.
- Hint: Separate find-slot from make-space.
Answer
- Short answer:
add= find-slot + make-space shift.- Why: Link-in-place ➔ a balanced Binary Tree inserts in by relinking a node, never shifting a contiguous block.
Compare a sorted array and a sorted linked list for maintaining order under inserts.
- Hint: Each is fast at one half, slow at the other.
Answer
- Short answer: Array = search / insert; linked = splice / find.
- Why: Random access dependency ➔ binary search needs midpoint (array only); the linked list can splice cheaply but can’t binary-search — a balanced Binary Tree achieves for both.