Quiz 3: Heaps & Priority Queues
Heap structure, array formulas, heapify operations, priority queue implementations, complexity and practice.
Heap Basics
What a heap is
- A heap has a binary tree structure.
- A heap is not a binary search tree.
- It must be an almost complete tree.
- Nodes on the last level must be as far left as possible.
- The lecture uses an array-based min-heap.
Valid min-heap example
10
/ \
20 40
/ \ / \
60 30 70 50
Each child is greater than its parent. The heap does not need to be fully sorted from left to right.
Heap vs. BST — quiz trap
| Structure | Ordering rule |
|---|---|
| Min-heap | Parent is smaller than its children |
| Binary Search Tree | Left subtree keys are smaller; right subtree keys are larger |
Array-Based Heap
Parent / child formulas — memorize these
Example from the heap layout
Index: 0 1 2 3 4 5 Value: 10 20 40 60 30 70
For the item 30, its index is i = 4.
| Relationship | Calculation | Result |
|---|---|---|
| Parent | ⌊(4 - 1) / 2⌋ | index 1 → 20 |
| Left child | 2(4) + 1 | index 9 |
| Right child | 2(4) + 2 | index 10 |
If those child indexes are outside the current heap size, the node has no child there.
Fast mental check
For index i = 5:
Parent = ⌊(5 - 1) / 2⌋ = 2 Left child = 2(5) + 1 = 11 Right child = 2(5) + 2 = 12
Heap Add & Heapify Up
How add works
- Copy the new item into the left-most open position on the last level.
- Compare the new item with its parent.
- If the new item is smaller than its parent, swap them.
- Continue moving upward until the heap property is restored.
Lecture-style pseudocode
Copy new item into left-most open item of last level
While item < parentOfItem
swap(item, parentOfItem)
item = parentOfItem
Example: add 5
Before
10
/ \
20 30
Insert at next open spot
10
/ \
20 30
/
5
Compare 5 with 20 → swap. Then compare 5 with 10 → swap.
5
/ \
10 30
/
20
Big-O
The copy into the open slot is O(1), while heapify up is O(log n). The total is therefore O(log n).
getMin & Heapify Down
What getMin does
In this lecture's heap implementation, getMin() returns and removes the root element.
- Save the root value in a local variable.
- Copy the right-most item on the last level into the root.
- Decrease the heap size.
- Compare the copied item with its children.
- If necessary, swap it with its smaller child.
- Continue downward until the heap property is restored.
- Return the saved minimum.
Lecture-style pseudocode
Save root into minVal
Copy right-most item of last level into root
item = root
While item > leastChildOfItem
swap(item, leastChildOfItem)
item = leastChildOfItem
return minVal
leastChildOfItem means the smaller of the left and right children.
Why the smaller child?
In a min-heap, the replacement value must end up below a value that is no greater than it. Choosing the smaller child preserves the min-heap ordering as the item moves down.
Big-O
Overwriting the root is O(1). Heapify down is O(log n). Total: O(log n).
Delete an Arbitrary Heap Item
How delete works
- Do a linear search through the array to find the item.
- Copy the right-most item on the last level into the deleted item's position.
- Check whether the replacement violates the heap property.
- If the replacement is smaller than its parent, heapify up.
- Otherwise, heapify down as necessary.
Big-O analysis
| Step | Cost |
|---|---|
| Find the item | O(n) |
| Replace it with last item | O(1) |
| Heapify up or down | O(log n) |
| Total | O(n) |
Priority Queue
Definition
A priority queue is an ADT in which only the item with the highest priority can be accessed.
- It is similar to a queue, but priority determines which item comes out first.
- The highest-priority item is logically at the front.
- Items can be represented as
<data, priority>pairs. - The most important operations in the lecture are
addandgetMin.
Lecture example: lower value = higher priority
The slides explicitly make this assumption for the example.
Insert:
14, 32, 11
Logical priority order:
Front → 11 → 14 → 32 → Rear
Then enqueue 22:
Front → 11 → 14 → 22 → 32 → Rear
Logical view vs. actual heap storage
A heap-based priority queue may feel fully ordered from the user's perspective, but the actual heap is not fully sorted.
Priority Queue Implementations & Big-O
The table to memorize
| Implementation | add | getMin | Main idea |
|---|---|---|---|
| Unsorted array | O(1) |
O(n) |
Add quickly; search for minimum later |
| Sorted array | O(n) |
O(n)* |
Maintain order; shifting is required |
| Heap | O(log n) |
O(log n) |
Balanced performance for both operations |
*The slides state getMin = O(n) for the sorted array implementation when items are shifted after removal.
Why the costs differ
add = O(1)
getMin = O(n)
No work is needed to preserve order during insertion, but locating the minimum requires a scan.
add = O(log n)
getMin = O(log n)
Heapify up and heapify down follow the height of the heap.
Quiz 3 Cram Sheet — Heaps & Priority Queues
Know these cold
-
Array formulas:
left = 2i + 1,right = 2i + 2,parent = ⌊(i - 1) / 2⌋. - Heapify direction: add → UP, getMin → DOWN, delete → UP or DOWN.
-
Heap Big-O:
add
O(log n), getMinO(log n), deleteO(n). -
Priority queue implementations:
unsorted array
O(1)/O(n), sorted arrayO(n)/O(n), heapO(log n)/O(log n).
Ultra-short version
MIN HEAP root = minimum parent <= children almost complete binary tree not a BST not fully sorted ARRAY INDEXES left = 2i + 1 right = 2i + 2 parent = floor((i - 1) / 2) HEAP OPERATIONS add → heapify UP → O(log n) getMin → heapify DOWN → O(log n) delete → O(n) PRIORITY QUEUE highest priority removed first lecture example: lower number = higher priority PQ IMPLEMENTATIONS unsorted array: add O(1), getMin O(n) sorted array: add O(n), getMin O(n) heap: add O(log n), getMin O(log n)
Common quiz traps
- A heap is not a BST.
- A heap is not fully sorted; only the heap property is guaranteed.
getMin()in these slides removes the root.- Heap add inserts at the next open position first, then heapifies up.
- Heapify down compares against the smaller child.
- Arbitrary delete is
O(n)because finding the item is linear. - The slide example assumes lower numbers have higher priority.
Quiz 3 Practice — Heaps & Priority Queues
Try these without looking above
- For a heap item at index
6, what are the indexes of its left child, right child, and parent? - In a min-heap, where is the smallest value located?
- When a new value is inserted into a min-heap, where is it placed before any swaps occur?
- Which operation normally uses heapify up:
addorgetMin? - During heapify down, which child should be used for the comparison in a min-heap?
- What are the Big-O costs of
add,getMin, and arbitrarydeletein the lecture's array-based heap? - For an unsorted-array priority queue, what are the Big-O costs of
addandgetMin? - For a heap-based priority queue, what are the Big-O costs of
addandgetMin? - Starting with an empty min-heap, insert
10, 7, 19, 5, 16. What value ends up at the root?
Mini heap tracing
Start with this min-heap:
4
/ \
9 7
/ \
15 12
- If
5is added, where is it inserted initially? - After heapify up finishes, what is the root?
- If
getMin()is then called, what value is returned? - After the root is removed, which existing item is copied into the root before heapify down?
Answer Key
Show all 13 answers
- Left = 13, right = 14, parent = 2.
- At the root.
- In the left-most open position on the last level.
- add. Add uses heapify up; getMin uses heapify down.
- The smaller / least child.
- add O(log n), getMin O(log n), delete O(n).
- add O(1), getMin O(n).
- add O(log n), getMin O(log n).
- 5.
- At the next open slot: the left child of 7.
- 4. The inserted 5 moves above 7 but not above 4.
- 4.
- The right-most item on the last level. With this insertion sequence, that item is 7.
Quiz 4: Sorting Algorithms & Hash Tables
Heapsort, selection sort, quicksort, Map ADT, hashing, collisions, separate chaining and resizing.
Heapsort
Main idea
The lecture's heapsort uses a min-heap.
- The heap holds the unsorted data.
- The array holds the sorted data.
- Repeatedly take the minimum element from the heap and place it into the next open location in the sorted region.
- This is similar to selection sort because both repeatedly select the minimum remaining item.
Heapsort pseudocode
Create an empty heap h
For all items in unsorted array
h.add(current item)
sortedNextOpen = 0
While heap not empty
min = h.getMin()
Copy min to array[sortedNextOpen]
Increment sortedNextOpen
Lecture example
Original list:
10, 7, 19, 5, 16
After all values are added to the min-heap:
5
/ \
7 19
/ \
10 16
Repeated getMin() calls produce:
5, 7, 10, 16, 19
Heapsort trace: build the min-heap (slides 7–12)
The lecture starts with [10, 7, 19, 5, 16] and inserts each value into an initially empty min-heap. Place it in the next open position of the complete tree, then heapify up if it is smaller than its parent.
| Insert | Heap in level-order array form | What changes? |
|---|---|---|
10 | [10] | 10 is the root. |
7 | [7, 10] | 7 swaps with parent 10. |
19 | [7, 10, 19] | 19 already satisfies the min-heap rule. |
5 | [5, 7, 19, 10] | 5 swaps upward past 10, then 7. |
16 | [5, 7, 19, 10, 16] | 16 stays below parent 7. |
Heap after all insertions:
5
/ \
7 19
/ \
10 16
[5,7,19,10,16], NOT the sorted sequence. Only the root is guaranteed to be the minimum.Source: Heapsort, pp. 7–12.
Heapsort trace: remove the minimum five times (slides 13–28)
getMin() removes the root in the lecture's heap implementation: move the last heap element into the root, reduce the heap size, and heapify down by swapping with the smaller child as needed. Then write the removed minimum to array[sortedNextOpen] and advance that index.
| Call | Removed min | Heap left afterward (level order) | Sorted array prefix |
|---|---|---|---|
| 1 | 5 | [7,10,19,16] | [5] |
| 2 | 7 | [10,16,19] | [5,7] |
| 3 | 10 | [16,19] | [5,7,10] |
| 4 | 16 | [19] | [5,7,10,16] |
| 5 | 19 | [] | [5,7,10,16,19] |
First removal in slow motion:
Start: [5, 7, 19, 10, 16]
Save min = 5; move last item to root:
[16, 7, 19, 10]
Swap 16 with smaller child 7:
[7, 16, 19, 10]
Swap 16 with smaller child 10:
[7, 10, 19, 16]
Write array[0] = 5; sortedNextOpen = 1
The other four removals follow the same remove → repair heap → append to sorted region pattern. After the fifth call, the heap is empty and the array is sorted.
Source: Heapsort, pp. 13–28. Heap contents are shown in array/level order to make each slide's tree easier to trace.
Heapsort Big-O
| Work | Cost |
|---|---|
| Create heap instance | O(1) |
| Add n items; each add is O(log n) | O(n log n) |
| Remove n items; each getMin is O(log n) | O(n log n) |
| Total | O(n log n) |
Heapsort best, average and worst cases (slides 30–31)
| Input (distinct keys) | Ω | O | Θ |
|---|---|---|---|
| Best: already sorted low to high | n log n | n log n | n log n |
| Average | n log n | n log n | n log n |
| Worst: sorted high to low | n log n | n log n | n log n |
Total for the method taught: O(1) + O(n log n) + O(n log n) = O(n log n).
O(n log n) either way.Source: Heapsort, pp. 30–31.
Selection Sort
Idea and algorithm
Selection sort is an elementary in-place sort. Divide the array into a growing sorted left part and a shrinking unsorted right part. To sort ascending, repeatedly find the minimum element in the unsorted part, swap it to the beginning of that part, and advance the boundary.
- Initialize
unsortedStart = 0. - Linearly search indexes
unsortedStartthrough the end for the minimum. - Swap the minimum with
data[unsortedStart](a swap may be unnecessary). - Increment
unsortedStart; repeat until everything is sorted.
Lecture walkthrough — 10, 7, 19, 5, 16
| Pass | Minimum | List after pass (bold = sorted) |
|---|---|---|
| Start | — | 10 7 19 5 16 |
| 1 | 5; swap with 10 | 5 7 19 10 16 |
| 2 | 7; no swap needed | 5 7 19 10 16 |
| 3 | 10; swap with 19 | 5 7 10 19 16 |
| 4 | 16; swap with 19 | 5 7 10 16 19 |
| 5 | 19; no swap needed | 5 7 10 16 19 |
unsortedStart = 0
while unsortedStart < n:
minIndex = unsortedStart
for j = unsortedStart + 1 to n - 1:
if data[j] < data[minIndex]:
minIndex = j
swap(data[unsortedStart], data[minIndex])
unsortedStart++
Source: Selection Sort, pp. 4–22. The overview once says “highest,” but the pseudocode and complete ascending trace clearly select the minimum.
Complexity / exam traps
- It searches each unsorted suffix even when the input is already sorted: best is still O(n²).
- Extra space: O(1), in-place.
- Stability: ordinary swap-based selection sort is not stable, although a stable variation can be written (as noted in the Quicksort slides).
Source: Selection Sort, pp. 24–25; Quicksort, pp. 5–6.
Quicksort
Divide and conquer + pivot
Quicksort recursively partitions an array around a pivot. Values below the pivot go left; values above the pivot go right. When a partition pass ends, the pivot occupies its final sorted position. Recursively sort the two remaining parts, excluding that pivot; stop at subarrays containing zero or one item.
Lecture trace: first pivot = 50
Original: 50 40 10 70 60 20 90 80 30 ^ pivot After one partition: 30 40 10 20 |50| 70 90 80 60 lower pivot higher
The pivot 50 is now in the correct place, but the elements within each partition are not yet fully sorted. Quicksort next sorts [30,40,10,20] and [70,90,80,60].
Source: Quicksort, pp. 7–8 and following partition slides.
First partition, step by step: i and j
Start with pivot 50 at index 0, i = 1 and j = 1. j scans the array; i is the next opening in the lower-than-pivot partition. The lower partition occupies indexes 1 through i - 1.
Scan index j | Compare with pivot 50 | i after processing |
|---|---|---|
1: 40 | Smaller: swap with itself | 2 |
2: 10 | Smaller: swap with itself | 3 |
3: 70 | Larger: no swap | 3 |
4: 60 | Larger: no swap | 3 |
5: 20 | Smaller: swap 20 with 70 at index 3 | 4 |
6: 90 | Larger: no swap | 4 |
7: 80 | Larger: no swap | 4 |
8: 30 | Smaller: swap 30 with 60 at index 4 | 5 |
Initial: 50 40 10 70 60 20 90 80 30 After processing j = 5 (20 swaps with 70): 50 40 10 20 60 70 90 80 30 After processing j = 8 (30 swaps with 60): 50 40 10 20 30 70 90 80 60 Scan complete: i = 5 Swap pivot data[0] with data[i - 1] = data[4]: 30 40 10 20 |50| 70 90 80 60
j after every examined item, but increment i only after moving an item below the pivot into the lower section. Finally, swap the pivot with data[i-1].Source: Quicksort, pp. 9–22.
Finish the lecture's Quicksort recursion
After placing pivot 50 at index 4, recursively sort the lower partition first, then the higher partition. Each recursive call picks the first element of its own subarray as the pivot.
| Subarray being sorted | Pivot | After this partition |
|---|---|---|
| Indexes 0–8 | 50 | 30 40 10 20 |50| 70 90 80 60 |
| Indexes 0–3 | 30 | 20 10 |30| 40 |
| Indexes 0–1 | 20 | 10 |20| |
| Indexes 5–8 | 70 | 60 |70| 80 90 |
| Indexes 7–8 | 80 | |80| 90 |
Recursive call order (first-element pivot):
quicksort(0,8) pivot 50
├─ quicksort(0,3) pivot 30
│ ├─ quicksort(0,1) pivot 20
│ │ ├─ quicksort(0,0) → base case
│ │ └─ quicksort(2,1) → empty
│ └─ quicksort(3,3) → base case
└─ quicksort(5,8) pivot 70
├─ quicksort(5,5) → base case
└─ quicksort(7,8) pivot 80
├─ quicksort(7,6) → empty
└─ quicksort(8,8) → base case
Final array:
10 20 30 40 50 60 70 80 90
Base case: if low >= high, there are zero or one elements in the region, so no partition is needed. After a partition, the pivot is already final; recursive calls exclude the pivot index.
Source: Quicksort, pp. 23–58; recursive call syntax summarized from the lecture's pseudocode on p. 59.
Partition pointers and pseudocode
| Symbol | Meaning in the lecture |
|---|---|
low | First index of current subarray and pivot location |
i = low + 1 | Next open slot for a value smaller than the pivot |
j | Index of element currently being inspected |
i - 1 | Final pivot index after scanning and swapping |
quicksort(low, high):
if low >= high: return
p = partition(low, high)
quicksort(low, p - 1)
quicksort(p + 1, high)
partition(low, high):
pivot = data[low]
i = low + 1
for j = low + 1 to high:
if data[j] < pivot:
swap(data[j], data[i])
i++
swap(data[low], data[i - 1])
return i - 1
data[j] < pivot, swap data[j] into the lower section and increment i. At the end, exchange the pivot with data[i-1].Big-O, recursion, and properties
| Case | Time | Reason |
|---|---|---|
| Best | O(n log n) | Balanced splits; log n levels |
| Average | O(n log n) | Typically reasonably balanced splits |
| Worst | O(n²) | Repeated partitions of sizes 0 and n − 1 |
- One partition of n values scans n items: O(n).
- Balanced recursion has about log n levels; terrible pivots yield about n levels.
- With a fixed first-element pivot, already sorted or reverse-sorted values may lead to the worst case.
- Quicksort rearranges the same array (in-place), although recursive calls need O(log n) average / balanced stack space and can reach O(n) worst case.
- Quicksort is not stable: duplicates need not retain their input order.
Source: Quicksort, pp. 5–6 and 60–64.
Randomized quicksort
Pick a pivot index uniformly at random, swap that value into the first slot, and perform the usual partition. A median pivot would balance the partitions ideally, but choosing the median is not required.
randIndex = randomly choose from low to high swap(data[low], data[randIndex]) // continue with first-element-pivot partition
- Expected: O(n log n), including for initially sorted input.
- Absolute worst case: O(n²); unlucky pivots are still possible.
Source: Quicksort, pp. 65–69.
Map ADT & Hashing Fundamentals
Map vs. hash table vs. hash set
- Map ADT: associates a unique key with a value, e.g.
"Yankees" → 1. - Operations:
add/put(key,value),find/get(key),delete/remove(key). - Hash table: an implementation of a map; alternatives include lists and binary search trees.
- Hash set: an unordered collection of unique values, not a collection of explicit key/value pairs.
- Hash function: transforms a key into an array index (the bucket) where its information is stored or searched for.
Bucket formula, collisions and a better hash
This is the lecture's simplified teaching example. With 10 buckets:
| Key | Math | Bucket |
|---|---|---|
| 52 | 52 % 10 | 2 |
| 71 | 71 % 10 | 1 |
| 43 | 43 % 10 | 3 |
| 41 and 91 | 41 % 10 = 91 % 10 | Both bucket 1 |
A collision occurs when different keys map to the same bucket. The slides explain that practical hashing usually transforms the key before using modulo, helping distribute keys more evenly.
hash(key):
transformedKey = transform(key)
return transformedKey % numBuckets
Searching costs — important comparison
| Structure | Find | Why? |
|---|---|---|
| Unsorted array or linked list | O(n) | Search each item |
| Balanced BST | O(log n) | Tree height |
| Hash table (good hash) | O(1) expected | Direct bucket + short chain |
SUHA, load factor and perfect hashing
Simple Uniform Hashing Assumption (SUHA): every key independently hashes to each bucket with equal probability. Under this assumption the expected bucket length is n/m, also called the load factor.
A perfect hash function has no collisions for a known set of keys. The slides note that it requires knowing possible keys beforehand; more keys than slots make collisions unavoidable.
Source: Hash Table Overview, pp. 3–6, 19–31.
Hash Table — Separate Chaining
How linked-list buckets handle collisions
Separate chaining uses an array of buckets, where each bucket is an unsorted linked list of nodes. Each node contains a key/value pair. Several different keys can occupy one bucket without replacing each other.
hash(key) = key % 10 bucket 0: [10] → [50] → [80] bucket 1: [91] → [11] → [71] bucket 2: [22] → [82] → [52] bucket 3: [33] bucket 4: [94] → [14] bucket 5: empty ... bucket 9: [49] → [19]
These diagrams show keys for simplicity, but the underlying nodes also hold values, e.g. <50, "Phone">.
Source: Separate Chaining, pp. 3–6.
add, find and delete
| Operation | Actions | Slide example |
|---|---|---|
add(key,value) | Compute bucket → insert node | 43 % 10 = 3; add <43,"Computer"> |
find(key) | Compute bucket → search only its list | 14 % 10 = 4; look in bucket 4 |
delete(key) | Compute bucket → remove matching node | 52 % 10 = 2; remove from bucket 2 |
add(key, value):
index = hash(key)
insert (key, value) into table[index]
find(key):
index = hash(key)
search table[index] for matching key
return its associated value if found
delete(key):
index = hash(key)
remove matching node from table[index]
Resize when projected load factor exceeds 0.75
Load factor = number of stored keys / number of buckets = n / m. The lecture checks before inserting: if the new item would make (n+1)/m > 0.75, resize.
| Before add | After add | Resize? |
|---|---|---|
| 2 keys / 4 buckets = 0.50 | 3/4 = 0.75 | No (not above 0.75) |
| 3 keys / 4 buckets = 0.75 | 4/4 = 1.00 | Yes |
| 6 keys / 8 buckets = 0.75 | 7/8 = 0.875 | Yes |
- Allocate a larger array (slides first illustrate roughly doubling the bucket count).
- Rehash and reinsert every existing key/value pair since its bucket may change.
- Insert the new entry.
Source: Separate Chaining, pp. 15–23.
Resize walkthrough from the slides: 16, 58, 19, 85
The lecture first uses exactly doubling as a simple illustration, starting with 2 buckets, hash(key) = key % bucketCount, and a threshold of 0.75.
| Action | Capacity / load factor | Where each key goes |
|---|---|---|
Start with 16 | 2 buckets; 1/2 = 0.50 | Bucket 0: 16 |
Add 58 | Projected 2/2 = 1.00; resize to 4 | Bucket 0: 16; bucket 2: 58 |
Add 19 | 3/4 = 0.75; no resize | Bucket 3: 19 |
Add 85 | Projected 4/4 = 1.00; resize to 8 | Bucket 0: 16; 2: 58; 3: 19; 5: 85 |
2 buckets, before adding 58: 0: [16] 1: [] 4 buckets, after adding 58 and 19: 0: [16] 1: [] 2: [58] 3: [19] 8 buckets, after adding 85: 0: [16] 1: [] 2: [58] 3: [19] 4: [] 5: [85] 6: [] 7: []
Source: Separate Chaining, pp. 15–23.
Why resizing by a constant amount breaks amortized O(1)
A resize takes O(n) because every stored key/value entry must be rehashed and inserted into the new array. The lecture's O(1) amortized insertion relies on increasing the array size by a multiplicative factor (doubling or close to doubling).
- Roughly doubling: after each resize, capacity for many future insertions is available. Cheap adds between resizes can account for the occasional expensive copy.
- Adding just 100 buckets each time: the number of adds between resizes stays roughly fixed while the number of elements copied at each resize keeps growing. The cheap adds cannot cover increasingly expensive copies at constant amortized cost.
- Tradeoff: expanding aggressively uses more unused buckets but makes resizing less frequent; expanding too slowly saves some capacity but increases copying work.
add that triggers resizing may cost O(n). The lecture's O(1) amortized claim describes the cost averaged across a sequence of adds with suitable geometric growth, not a guarantee for every add.Source: Separate Chaining, pp. 17, 22–23 and 25–28 (especially the fixed-100-bucket counterexample on p. 26).
Performance — expected, amortized and worst case
| Operation | Good hash + proper resizing | Possible worst case |
|---|---|---|
add | O(1) amortized | O(n) if resizing |
find | O(1) expected | O(n) long collision chain |
delete | O(1) expected | O(n) long collision chain |
resize | O(n) | O(n) |
Amortized O(1) add means occasional expensive resizing is spread across many inexpensive additions. Expected O(1) find and delete depend on good hashing (SUHA) and periodic resizing — they are not hard worst-case guarantees.
Source: Separate Chaining, pp. 17, 25–29.
Quiz 4 Cram Sheet — Sorting & Hashing
Sorting Big-O comparison
| Algorithm | Best | Average | Worst |
|---|---|---|---|
| Selection sort | O(n²) | O(n²) | O(n²) |
| Quicksort | O(n log n) | O(n log n) | O(n²) |
| Randomized quicksort | O(n log n) | O(n log n) expected | O(n²) absolute |
| Heapsort (earlier lesson) | O(n log n) | O(n log n) | O(n log n) |
Nine facts to memorize
- Selection: repeated minimum + swap; Θ(n²) even on sorted input.
- Quicksort: pivot is final after partition; recursively sort either side.
- Randomized quicksort: expected O(n log n), absolute worst O(n²).
- Map: key/value pairs; set: unique values.
- Hash function: key → bucket; two keys at one bucket → collision.
- Separate chaining: bucket = unsorted linked list of key/value nodes.
- Load factor: n/m; resize on add when projected factor > 0.75 in lecture.
- Resize: all keys are rehashed into new buckets, O(n).
- Hash costs: add O(1) amortized; find/delete O(1) expected with good hashing and resizing.
Quiz 4 Practice — Sorting Algorithms
Selection Sort, Quicksort & Heapsort
- In the lecture's heapsort, insert
10, 7, 19, 5, 16into an empty min-heap. What is the heap's final level-order array before removals? - What sorted output does repeated
getMin()produce for those five values, and what is heapsort's overall Big-O runtime? - What does
unsortedStartrepresent in selection sort? - After one selection sort pass on
[10,7,19,5,16], what is the array? - What are selection sort's best, average and worst runtimes?
- Why does an already sorted array not speed up selection sort?
- Which element is chosen as pivot in the main quicksort lecture?
- After a partition pass, what is guaranteed about the pivot?
- What is the lecture's first partition result for
[50,40,10,70,60,20,90,80,30]? - What do
iandjtrack while partitioning? - What is the quicksort recursion base case?
- What split pattern produces O(n²) quicksort performance?
- What are randomized quicksort's expected and absolute worst-case runtimes?
Answer key
Show all 13 answers
[5,7,19,10,16]. The heap obeys the parent-child ordering rule but is not completely sorted.[5,7,10,16,19], with overall time O(n log n).- The index where the unsorted portion begins.
[5,7,19,10,16].- Θ(n²) in every case.
- Selection sort still scans the whole remaining suffix for its minimum on each pass.
- The first element of the current subarray.
- The pivot is in its final sorted position.
[30,40,10,20,50,70,90,80,60].imarks the next lower-partition slot;jscans input.low >= high(zero or one element).- Each pivot divides into 0 elements and n−1 elements.
- Expected O(n log n), absolute worst O(n²).
Quiz 4 Practice — Hash Tables
Hashing, Load Factor & Separate Chaining
- Name the three Map ADT operations.
- Under
key % 10, what is the bucket for 87? - Do keys 11 and 71 collide in a 10-bucket table? Why?
- What is stored in each node of a separate-chaining table?
- Where do you search for key 14 in a table of 10 buckets using modulo?
- What is the load factor for 75 keys and 100 buckets?
- With 6 keys and 8 buckets, would adding a seventh cause a resize under the lecture's threshold?
- Why does a resized table need to rehash all the keys?
- What is the runtime of resizing a hash table?
- Explain the difference between amortized O(1) add and expected O(1) find.
- Name a system where the lecture suggests a balanced BST instead of a hash table.
Answer key
Show all 11 answers
- add/put, find/get, delete/remove.
- 7.
- Yes; both keys have remainder 1 modulo 10.
- The key/value pair (with a link to the next node).
- Search the linked list in bucket 4.
- 0.75.
- Yes; 7/8 = 0.875, above 0.75.
- The bucket indices depend on the table's size, which changes.
- O(n), due to rehashing every existing entry.
- Amortized: costly resizes averaged over many cheap inserts. Expected: typical constant lookup under good hashing and resizing, not guaranteed in worst case.
- A strict real-time system like air traffic control or critical hospital equipment.