Midterm review: sorting, trees, BST, AVL, heap
A one-page summary of weeks 1-8: the Big-O table, the tracing pattern for each topic and mixed midterm questions.
Midterm week. This page does not teach a new topic; it collects the first eight weeks in one place. First look at the summary table, then read the “how to solve it in the exam” pattern for each topic, and finally solve the questions with pen and paper. Do not open the answer to a question before working out your own trace.
The question types you will meet in the midterm are almost fixed:
- Big-O: best, average and worst time for a structure or algorithm.
- Tracing: “insert in this order, draw the tree/array”.
- Writing a method: recursive tree methods: height, leaf count, sum, search.
The big table
| Structure / algorithm | Operation | Best / average | Worst | Note |
|---|---|---|---|---|
| Merge sort | sorting | stable, extra memory | ||
| Quicksort | sorting | in place, unstable | ||
| Heapsort | sorting | in place, unstable | ||
| Counting sort | sorting | k = value range | ||
| Radix sort | sorting | d digits, stable sub-sort | ||
| Tree traversal | pre/in/post/level | each node once | ||
| BST | find/insert/remove | a chain with sorted insertion | ||
| AVL | find/insert/remove | height ≤ ~1.44 log n | ||
| Binary heap | insert | avg. | percolate up | |
| Binary heap | deleteMin | percolate down | ||
| Binary heap | findMin | root | ||
| Binary heap | buildHeap | n inserts would be |
Sorting: what to remember
The lower bound. An algorithm that only makes comparisons is a decision tree. Each of the different orderings must end in a separate leaf. Since a binary tree of height h has at most leaves:
n n! minimum comparisons
3 6 3
4 24 5
5 120 7
6 720 10
8 40320 16
Why do counting and radix get past this bound? Because they make no comparisons. They use the value itself as an array index. The price: the values must be small integers (or fixed-length keys).
An LSD radix trace. In each pass, distribute stably (stable) by one digit and collect the buckets in order:
start 512 34 208 71 645 93 160
ones 160 71 512 93 34 645 208
tens 208 512 34 645 160 71 93
hundreds 34 71 93 160 208 512 645
PITFALL · stability in radix. In the tens pass 208 and 512 go to different buckets, but numbers that fall in the same bucket must keep the order of the previous pass. If you break stability, the work of the previous pass is lost.
Trees and traversals
You should be able to solve this tree from memory:
A
/ \
B C
/ \ \
D E F
/
G
preorder A B D E G C F (root, left, right)
inorder D B G E A C F (left, root, right)
postorder D G E B F C A (left, right, root)
level A B C D E F G (with a queue)
height 3, leaf count 3 (D, G, F)
Building a tree from preorder + inorder. The first element of the preorder is the root. Find the root in the inorder: what is to its left is the left subtree, and what is to its right is the right subtree. The next element in the preorder is the root of the left subtree. Continue recursively.
pre: 5 9 1 3 7 2 8 in: 1 9 7 3 5 2 8
root 5: in -> [1 9 7 3] 5 [2 8]
left root 9: in -> [1] 9 [7 3]
right of 9, root 3: in -> [7] 3
right root 2: in -> 2 [8]
5
/ \
9 2
/ \ \
1 3 8
/
7
post: 1 7 3 9 8 2 5
With only preorder + postorder the tree is not unique (it is unknown whether the child of a single-child node is on the left or the right). The inorder is required.
BST: insertion and deletion
Insert 45, 20, 60, 10, 30, 50, 70, 25, 35:
45
/ \
20 60
/ \ / \
10 30 50 70
/ \
25 35
The three cases of deletion: if it is a leaf, delete it directly. If there is one child, link the child to the parent. If there are two children, replace its value with the inorder successor (the leftmost of the right subtree), then delete the successor from the right subtree (it has at most one child).
Delete 20: the successor is 25.
45
/ \
25 60
/ \ / \
10 30 50 70
\
35
Preorder: 45 25 10 30 35 60 50 70. If you then delete 45, the successor is 50: 50 25 10 30 35 60 70.
AVL: choosing the rotation
Going up the insertion path from the bottom, the first node whose BF is +2 or -2 is the rotation point. Choose the case by looking from there, according to which grandchild the insertion was made in:
| Where the insertion went | BF | Rotation |
|---|---|---|
| left of the left child (LL) | +2 | single right |
| right of the right child (RR) | -2 | single left |
| right of the left child (LR) | +2 | first left at the child, then right |
| left of the right child (RL) | -2 | first right at the child, then left |
Insert 40, 20, 60, 10, 30, then insert 25:
before (25 inserted) after (LR at 40)
40 30
/ \ / \
20 60 20 40
/ \ / \ \
10 30 10 25 60
/
25
The BF of 40 is 2 - 0 = 2, and the insertion went to the right of the left child (20): LR. The median value (30) moves up.
Heap: buildHeap and heapsort
buildHeap sinks every node from the last internal node of the array (n/2) toward the root. Most nodes are on the lower levels and sink only a little; the total work is .
[9, 4, 7, 1, 8, 2, 6] n=7, i=3..1
i=3 7 <-> 2 [9, 4, 2, 1, 8, 7, 6]
i=2 4 <-> 1 [9, 1, 2, 4, 8, 7, 6]
i=1 9 -> 1 -> 4 [1, 4, 2, 9, 8, 7, 6]
Heapsort builds a max-heap for ascending order (0-indexed: children 2i+1, 2i+2). Then at each step it places the root (the largest) at the end of the active part of the array and shrinks the heap by one.
[3, 8, 5, 1, 9, 6]
buildHeap [9, 8, 6, 1, 3, 5]
step 1 [8, 5, 6, 1, 3 | 9]
step 2 [6, 5, 3, 1 | 8, 9]
step 3 [5, 1, 3 | 6, 8, 9]
step 4 [3, 1 | 5, 6, 8, 9]
step 5 [1 | 3, 5, 6, 8, 9]
For priority queues and java.util.PriorityQueue, see the other page of this week.
Common mistakes
| Wrong idea | The truth |
|---|---|
| In radix, use any sort you like in each pass | The sub-sort must be stable |
| Pre + post determines the tree uniquely | The inorder is needed |
| In deletion, the successor = the right child | The leftmost node of the right subtree |
| In AVL, rotate at the topmost node with a broken BF | At the lowest broken node on the path |
| A single right rotation is enough for LR | A double rotation: first left at the child |
| buildHeap is | ; n inserts are |
| A min-heap for ascending heapsort | A max-heap for in-place ascending order |
| The height of a single node is 1 | In this course 0; an empty tree is -1 |
Test yourself
Exam-style questions. Solve them on paper first, then reveal the answer.
What is the minimum number of comparisons that any comparison-based algorithm needs, in the worst case, to sort 6 elements?
Show answer
The decision tree must have at least leaves. A binary tree of height h has at most leaves: . , so .
Apply LSD radix sort (base 10) to [512, 34, 208, 71, 645, 93, 160]. Give the array after the first pass and after the second pass.
Show answer
Pass 1 by the ones digit (stable): 160(0), 71(1), 512(2), 93(3), 34(4), 645(5), 208(8).
Pass 2 by the tens digit, equal digits keep the previous order: 208(0), 512(1), 34(3), 645(4), 160(6), 71(7), 93(9).
Pass 3 by the hundreds digit gives the sorted array: [34, 71, 93, 160, 208, 512, 645].
Which of merge sort, quicksort and heapsort is both stable and in the worst case?
- merge sort
- quicksort
- heapsort
- none of them
Show answer
Merge sort is stable if it takes the left element first on ties, and it is in every case. The worst case of quicksort is and it is not stable. Heapsort is but not stable (it makes long-distance swaps).
For the tree below, give the postorder and level-order traversals.
A
/ \
B C
/ \ \
D E F
/
GShow answer
Postorder = left, right, root. Under B: D, then under E (G, E), then B. Then under C: F, C. Finally A.
Level-order: level by level from left to right. A | B C | D E F | G.
(Preorder A B D E G C F, inorder D B G E A C F.)
A binary tree has preorder 5 9 1 3 7 2 8 and inorder 1 9 7 3 5 2 8. Give its postorder traversal.
Show answer
The first element of the preorder is the root: 5. In the inorder, the left of 5 is {1 9 7 3} and the right is {2 8}.
Left subtree: the next in the preorder, 9, is the root. Inorder {1 | 9 | 7 3}: its left is 1, its right is {7 3}. The next one, 3, is the root, and in the inorder {7 3}, 7 is its left child.
Right subtree: the root is 2, inorder {2 8} → 8 is the right child.
Postorder: 1, 7, 3, 9, 8, 2, 5.
Insert 45, 20, 60, 10, 30, 50, 70, 25, 35 into an empty BST, then delete 20 (use the inorder successor). Give the preorder traversal of the result.
Show answer
Preorder before the deletion: 45 20 10 30 25 35 60 50 70.
20 has two children. The inorder successor = the smallest of the right subtree = 25. 25 is written in place of 20, then 25 is deleted from the right subtree (a leaf). The left of 30 becomes empty.
The resulting preorder: 45 25 10 30 35 60 50 70.
Keys 1, 2, 3, 4, 5, 6, 7 are inserted in this order into (a) a plain BST and (b) an AVL tree. What is the height of each tree? (A single node has height 0.)
Show answer
In a plain BST, sorted insertion produces a chain extending to the right: 7 nodes, 6 edges, height 6. The AVL tree performs four RR (single left) rotations and builds the perfect tree: preorder 4 2 1 3 6 5 7, height 2.
Insert 40, 20, 60, 10, 30, 25 into an empty AVL tree. Which rotation happens, at which node, and what is the preorder traversal afterwards?
Show answer
When 25 is inserted, the path is 40 → 20 → 30 → 25 (left). Heights: h(20)=2, h(60)=0, the BF of 40 = 2 - 0 = 2.
The insertion was made in the RIGHT subtree of the LEFT child of 40: the LR case.
First a left rotation at 20 (30 moves up), then a right rotation at 40. The new root is 30; its left is 20 (with children 10 and 25), and its right is 40 (with right child 60).
Run buildHeap (min-heap, array starting at index 1) on [9, 4, 7, 1, 8, 2, 6]. Give the resulting array.
Show answer
n = 7, sink from i = n/2 = 3 down to 1.
i=3: 7, the children are 2 and 6, the smaller is 2 → [9, 4, 2, 1, 8, 7, 6]
i=2: 4, the children are 1 and 8 → 1 moves up → [9, 1, 2, 4, 8, 7, 6]
i=1: 9, the children are 1 and 2 → 1 moves up; 9 is at index 2, the children are 4 and 8 → 4 moves up → [1, 4, 2, 9, 8, 7, 6]
Heapsort (max-heap, 0-indexed) is applied to [3, 8, 5, 1, 9, 6]. Give the array after buildHeap and after the first deleteMax step (swap root with last, percolate down).
Show answer
buildHeap: i = 2, 1, 0. i=2: 5 < 6 → [3, 8, 6, 1, 9, 5]. i=1: 8 < 9 → [3, 9, 6, 1, 8, 5]. i=0: 3, the larger child 9 → moves up; 3 is at index 1, the larger child 8 → moves up → [9, 8, 6, 1, 3, 5].
Step 1: 9 is swapped with the last element 5 → [5, 8, 6, 1, 3 | 9]. Sink 5 within the first 5 elements: 8 moves up, then the children are 1 and 3, both smaller than 5 → stop: [8, 5, 6, 1, 3, 9].
Write a recursive method int height(Node t) for a binary tree, where an empty tree has height -1 and a single node has height 0.
Show answer
The empty tree is the base case. For every other node, add 1 to the larger of the heights of the two subtrees.
static int height(Node t) {
if (t == null) return -1;
return 1 + Math.max(height(t.left), height(t.right));
}For the lettered tree above (A...G) the result is 3 (A → B → E → G). Each node is visited once: .
Give the worst-case time of search in (a) a BST with n nodes, (b) an AVL tree with n nodes, and (c) findMin in a binary min-heap.
Show answer
A plain BST turns into a chain with sorted insertion, so search is . AVL always keeps the height , so search is . In a min-heap the smallest is always at the root: . But searching for an arbitrary element in a heap is .
Verification: All traces (radix passes, traversal orders, building a tree from preorder+inorder, BST deletion, AVL rotations, buildHeap, heapsort steps) were coded in Java and run (verify/SEN2212/W08R.java, java W08R.java).