Chapter 10: Search Trees
Multiple Choice · Search Trees
Question 1: The BST Property
Trees are written as root(left, right) (— means empty). Which of these is not a binary search tree?
C: 12 is right of 5, so it must exceed 5, but it is also in 10's left subtree, so it must be less than 10 too. The BST property covers whole subtrees, not just children. In B, 7 is between 5 and 10, so B is valid.
Multiple Choice · Search Trees
Question 2: A Buggy minValue
Here is a version of minValue. What does minValue(root) return for a non-empty tree?
BinaryTreeNode<E> minValue(
BinaryTreeNode<E> node) {
while (node != null)
node = node.leftChild;
return node;
}The loop runs until node is null, walking past the leftmost node and returning null. No field of null is accessed, so no exception (C is wrong). The fix: while (node.leftChild != null); the minimum is the leftmost node, the one with no left child; O(h).
Multiple Choice · BST Operations
Question 3: Comparing with ==
1000, 100, and 2000 were added to the tree with insert, in that order. What does this search print?
boolean search(BinaryTreeNode<Integer> root, Integer data) { if (root == null) return false; if (data == root.data) return true; if (data.compareTo(root.data) < 0) return search(root.leftChild, data); return search(root.rightChild, data); } System.out.println(search(root, 1000));
== compares Integer references, and two separately boxed 1000s are different objects. compareTo returns 0, so the code goes right (to 2000) and hits the null on 2000's left → false. The fix: k = data.compareTo(root.data); k == 0 means found.
Short Answer · BST Operations
Question 4: Insertion Order and Tree Shape
Insert 45, 20, 70, 10, 30, 60, 90, 25, 65, 27 in that order into an empty BST. Draw the final tree and give its height.
Show answer
Each key descends from the root (left if smaller, right if larger) and becomes a leaf where it hits null. E.g., 27: 45 → 20 → 30 → 25 → right of 25.
Height 4 (the path 45–20–30–25–27).
Check with an inorder traversal: 10 20 25 27 30 45 60 65 70 90
Short Answer · BST Operations
Question 5: Dropping the Return Value
The slides' insert (which returns the new subtree root) is used as below. What is printed? Explain.
BinaryTreeNode<Integer> root = null;
insert(root, 8);
insert(root, 3);
insert(root, 12);
inorder(root);
Show answer
Nothing is printed; the tree stays empty. Java passes arguments by value: insert(null, 8) returns the new node, but it is never assigned, so it is lost and root stays null.
The fix: root = insert(root, 8); (and likewise for delete).
On a non-empty tree the unassigned call often seems to work, since the inner call links the new leaf via root.leftChild = …. But whenever the root changes (empty tree, deleting the root, a rotation at the root of a balanced tree), the tree breaks.
Short Answer · BST Operations
Question 6: Successor, Predecessor, Ceiling, Floor
For the BST shown, find successor(45), predecessor(50), ceiling(38), and floor(38), naming the rule you used for each.
Show answer
- successor(45) = 50: 45 has no right subtree → the nearest ancestor we reach from its left (45 is in 50's left subtree).
- predecessor(50) = 45: the largest key in the left subtree: one step left (30), then right all the way → 40 → 45.
- ceiling(38) = 40: the smallest key ≥ 38 (38 is not in the tree).
- floor(38) = 35: the largest key ≤ 38.
Each follows a single path from the root: O(h). The TreeMap equivalents are higherKey, lowerKey, ceilingKey, and floorKey.
Code Trace · BST Operations
Question 7: Tracing successor()
In the tree shown, which node does successor(root, 62) return? (62 is not in the tree.)
No candidate yet; start at the root (50).
62 ≥ 50 → neither 50 nor anything to its left can be the successor; go right.
62 < 70 → 70 is a candidate; a smaller one can only be on the left → go left.
62 ≥ 60 → go right.
62 < 65 → candidate = 65 (better than 70); go left: root = null.
The loop ends → return 65. We visited 4 nodes: O(h).
TreeNode successor(TreeNode root, int x) { TreeNode candidate = null; while (root != null) { if (x < root.data) { candidate = root; // candidate root = root.left; // left } else root = root.right; // right } return candidate; } System.out.println(successor(root, 62).data);
Short Answer · BST Operations
Question 8: Deletion: Three Cases
Delete 20, 30, and 50, in that order, from the BST shown (use the inorder successor for two-child nodes). Name each deletion's case and draw the final tree.
Show answer
- delete 20: a leaf → 30's left link becomes null.
- delete 30: it now has only a right child (40) → one child: 50 links directly to 40.
- delete 50: two children → successor = smallest key on the right, 60; 60 is copied into the root and the old 60 (only child: 65) is deleted → 65 becomes 70's left child.
Inorder: 35 40 45 60 65 70 80
Multiple Choice · BST Operations
Question 9: The Successor's Children
Deleting a node with two children copies in its inorder successor, then deletes the successor itself. Why is that second deletion always a leaf or one-child case?
minValue goes left until a node has no left child. The successor may have a right child (B and D are wrong) and may sit deeper down (C is wrong). Symmetrically, the predecessor has no right child.
Code Trace · BST Operations
Question 10: Tracing range()
In the tree shown, what does range(root, 38, 62) print, and which nodes are never visited?
38 < 50 → there may be keys in range on the left: go left.
38 < 30 is false → the left subtree (20) is pruned. 30 is out of range. 30 < 62 → go right.
38 < 40 → go left.
35: left pruned, out of range; 35 < 62 → go right (null), returns at once.
Back at 40: 40 ∈ [38, 62] → print.
40 < 62 → go right: 45. Left empty; 45 in range → print. Right empty too.
The frames for 45, 40, and 30 close; back at 50: 50 is in range → print.
50 < 62 → go right: 70. 38 < 70 → go left.
60: its left is empty; 60 is in range → print. 60 < 62 → go right.
65 is out of range; 65 < 62 is false → its right is pruned.
Back at 70: out of range; 70 < 62 is false → 80 is pruned.
The output is sorted: 40 45 50 60. 20 and 80 were never visited → O(h + s).
void range(TreeNode k, int lo, int hi) { if (k == null) return; if (lo < k.data) // candidates on the left range(k.left, lo, hi); if (lo <= k.data && k.data <= hi) System.out.print(k.data + " "); if (k.data < hi) // candidates on the right range(k.right, lo, hi); }
Multiple Choice · Balance and AVL Trees
Question 11: An Order for a Perfect Tree
In which order should the keys 1, 2, …, 7 be inserted into an empty BST to get a (perfect) tree of height 2?
The middle first (4), then each half's middle (2, 6), the leaves last. In B, 1–2–3 and 5–6–7 become chains (h = 3); in C the root 2 leaves the right side heavy (h = 3); A is a chain with h = 6. A BST's shape depends on the insertion order.
Short Answer · Balance and AVL Trees
Question 12: Balance Factor and Rotation
The figure shows an AVL tree just after inserting 27, before rebalancing. Compute the balance factors, decide which rotation goes at which node, and draw the result.
Show answer
bf = h(left) − h(right), with −1 for an empty subtree. From 27 up to the root: bf(25) = −1, bf(20) = 0 − 1 = −1, bf(15) = 0 − 2 = −2 ✗, bf(30) = 3 − 1 = 2 ✗.
Fix the lowest unbalanced node, 15: right-heavy, with right child 20 at bf = −1 (same direction) → RR: a left rotation at 15.
The subtree's height returns to 2, so 30 is balanced again too (bf = 1).
Multiple Choice · Balance and AVL Trees
Question 13: Which Rotation?
Insert 50, 20, 30 in that order into an empty AVL tree. Which case arises, and how is the tree rebalanced?
bf(50) = 2 (left-heavy), but the left child 20 has bf = −1 (leaning right): a zigzag (triangle) → LR. A single right rotation (A) gives 20(—, 50(30, —)) with bf(20) = −2, still unbalanced. The correct result is 30(20, 50).
Short Answer · Balance and AVL Trees
Question 14: A Sequence of AVL Insertions
Insert 40, 20, 10, 25, 30, 22, 50 in that order into an empty AVL tree. Name the case (LL, RR, LR, RL) and the rotations for each imbalance, and draw the final tree.
Show answer
- +10: bf(40) = 2, bf(20) = 1 → LL: right at 40 → 20(10, 40).
- +25: left of 40; no imbalance.
- +30: right of 25; bf(40) = 2, bf(25) = −1 → LR: left at 25, right at 40 → 20(10, 30(25, 40)).
- +22: left of 25; bf(20) = −2, bf(30) = 1 → RL: right at 30, left at 20 → 25(20(10, 22), 30(—, 40)).
- +50: bf(30) = −2, bf(40) = −1 → RR: left at 30.
The final tree: all four cases appeared along the way; h = 2.
Multiple Choice · Red-Black Trees
Question 15: Which Rule Is Broken?
In the figure, the dark nodes are black and 40 is red; empty children (NIL) count as black. Which red-black tree rule does this tree break?
20 → 10 → NIL has 2 blacks (20, 10), but 20 → 30 → 25 → NIL has 3 (20, 30, 25). The only red node, 40, has NIL (black) children, and the root is black. Making 25 red gives every path 2 blacks, and the tree becomes valid.
Short Answer · Red-Black Trees
Question 16: Inserting into a Red-Black Tree
Insert 50, 40, 30, 35, 45, 32 in that order into an empty red-black tree. Name the case for each insertion that needs fixing, and draw the final tree with colors.
Show answer
- 50: the root → black. 40: the parent is black, nothing to do.
- 30: parent 40 is red, the uncle is NIL (black), and 30–40–50 is a line → rotate right at 50; 40 black, 50 red.
- 35: parent 30 and uncle 50 are red → recolor: 30 and 50 black, 40 red; 40 is the root, so it turns black again.
- 45: parent 50 is black, nothing to do.
- 32: parent 35 is red, the uncle is NIL; 32–35–30 is a triangle → rotate right at 35 (a line), then left at 30; 32 black, 30 red.
Every path has 2 black nodes, and no two reds are adjacent.
Multiple Choice · Red-Black Trees
Question 17: AVL or Red-Black?
Which choice suits a large, rarely updated dictionary in which 95% of operations are searches?
Both give O(log n), but AVL builds a shorter tree, and its costlier updates (O(log n) rotations on deletion) hardly matter when updates are rare. A has it backwards: red-black trees are balanced more loosely; their cheap updates (≤ 2–3 rotations, 1 color bit) make them the choice for frequently updated structures and libraries (TreeMap, std::map).
Code Trace · Splay Trees
Question 18: Tracing splay()
In the splay tree shown, we access 10. What steps does splay(10) take, and what is the final tree?
x is not the root. p = 20, g = 30.
g exists, and x and p are both left children → same side: zig-zig.
The grandparent first: rotate right at 30 → 20 moves up.
Then the parent: rotate right at 20 → x has risen two levels.
x is still not the root. p = 50 is the root, g = null.
g == null → zig: rotate right at 50; 10 becomes the root, and its old right subtree (20…) becomes 50's left.
x == root → the loop ends. A zig comes only as the last step; a zig-zig rotates the grandparent first.
void splay(Node x) { while (x != root) { Node p = x.parent, g = p.parent; if (g == null) // zig rotate(p, x); else if (sameSide(x, p, g)) { rotate(g, p); // grandparent first rotate(p, x); } else { // zig-zag rotate(p, x); rotate(g, x); } } }
Short Answer · Multiway Search Trees
Question 19: B-Tree Insertion
Insert 40, 10, 30, 20, 50, 60, 70, 80 in that order into an empty B-tree of order m = 3 (at most 2 keys per node). Draw the final tree. How many times does the root split?
Show answer
- 30: [10 30 40] overflows → median 30 is the new root over [10] and [40] (root split 1).
- 20 → [10 20]; 50 → [40 50]; 60: [40 50 60] overflows → 50 moves up: root [30 50].
- 70 → [60 70]; 80: [60 70 80] overflows → 70 moves up, root [30 50 70] overflows → 50 is the new root (root split 2).
The root split twice; the height grew only on root splits, and all leaves stayed at the same depth. A B-tree grows upward.
Multiple Choice · Multiway Search Trees
Question 20: Range Queries in a B+ Tree
A database index serves frequent range queries such as “between 20 and 50.” Which property makes a B+ tree better than a B-tree for this job?
D. The leaf holding the lower bound 20 is found in O(log n); then the leaf chain is followed without climbing back up: O(log n + k) in total, k = number of results. A describes a B-tree; in a B+ tree internal nodes hold only routing keys, so more keys fit in a block and the tree is shallower.
Open-Ended Question · Summary
Question 21: A Dictionary App
A dictionary app must add words, look words up, and list all words starting with "ab" alphabetically; at setup, the words are bulk-loaded in alphabetical order. Would you pick a HashMap, a plain BST, or a TreeMap (a red-black tree)? Justify.
Sample answer
A HashMap gives O(1) average insertion and lookup but keeps no order; a prefix query must scan the whole table and sort the result (O(n + k log k)).
A plain BST is ordered, but alphabetical loading puts each word right of the previous: a chain, h = n − 1, O(n²) to load, O(n) per operation.
A TreeMap keeps keys sorted and uses rotations to guarantee h = O(log n), so sorted loading is fine. A prefix query is a range query: subMap("ab", "ac") takes O(log n + k) and returns the words already sorted. For prefix-heavy work, a specialized structure (a trie) is also worth considering.
Short Answer · Balance and AVL Trees
Question 22: A Chain of AVL Fixes After Deletion
Delete 60 from the AVL tree shown. The course's delete does a BST deletion, then calls rebalance at each ancestor as the recursion unwinds. Which rotations happen at which nodes on the way up? Draw the final tree.
Show answer
bf = h(left) − h(right), with −1 for an empty subtree.
- 60 is a leaf → it is cut off. 55: bf = 1 − (−1) = 2 ✗, bf(50) = 1 → LL: right at 55 → 50(45, 55). This subtree's height drops from 2 to 1.
- 40: bf = 3 − 1 = 2 ✗, bf(15) = 1 − 2 = −1 → LR: left at 15 (30 moves up), then right at 40.
3 rotations at two ancestors; the height drops from 4 to 3. An insertion needs one fix, but in a deletion a rotation can shorten a subtree and push the imbalance upward: rotations at up to O(log n) ancestors.
Multiple Choice · Balance and AVL Trees
Question 23: A Child with bf = 0 on Deletion
We delete 60 from the AVL tree 50(30(20, 40), 60). What does the call to rebalance at 50 do?
if (bf(d) > 1) { // left-heavy if (bf(d.left) < 0) // LR d.left = rotateLeft(d.left); return rotateRight(d); // LL }
B: with 60 gone, bf(50) = 1 − (−1) = 2, and the left child 30 has bf = 0. This arises only on deletion, never on insertion; bf(d.left) < 0 is false, so the code does a single right rotation, and 40 moves from 30's right to 50's left. A would also give a balanced tree (40(30(20, —), 50)), but the code does no double rotation here. C: bf = 2 is a violation. D: the height stays 2, as before the deletion.