Asymptotic Complexity, Recurrences, Searching, Sorting and Hashing
Sorting: Two Families and a Lower Bound
| Algorithm | Worst case | Extra space | Stable? |
|---|---|---|---|
| Merge sort | Θ(n log n) | Θ(n) | Yes |
| Quicksort | Θ(n²) | Θ(log n) stack | No |
| Heapsort | Θ(n log n) | Θ(1) | No |
| Insertion sort | Θ(n²) | Θ(1) | Yes |
| Counting sort | Θ(n + k) | Θ(k) | Yes |
Hashing, Honestly
A hash table is O(1) expected and O(n) worst case, and both halves matter. With n keys in m slots the load factor is α = n/m, and under chaining a successful search examines about 1 + α/2 entries — constant as long as α is bounded. But nothing prevents every key from hashing to one slot, and then the table is a linked list: O(n). Open addressing with linear probing has a second failure mode, primary clustering, where occupied runs grow and lengthen every probe that lands in them; quadratic probing and double hashing scatter the probe sequence to break the runs up.
Key takeaways
- An asymptotic bound names a case: quicksort is O(n log n) average and Θ(n²) worst, both true.
- Master theorem: compare f(n) with nlog_b a; whichever dominates wins, a tie adds a log.
- T(n) = T(n−1) + n is not of master-theorem form — the depth is n, so it is Θ(n²).
- Ω(n log n) is a lower bound on the comparison-sorting problem, from log₂(n!) decision-tree height.
- Counting sort beats it only by not comparing, and pays with a Θ(k) dependence on the key range.
- Heapsort is the Θ(n log n) sort with Θ(1) extra space; merge sort needs Θ(n).
- Maximum and minimum together take ⌈3n/2⌉ − 2 comparisons, not 2n − 2 — 148 against 198 at n = 100.
- Hashing is O(1) expected and O(n) worst case; linear probing adds primary clustering.
Practice questions (8)
Attempt each one before opening the answer. Every explanation names the tempting wrong option as well as the right one, because that is where marks are lost.
The recurrence T(n) = 3T(n/2) + n solves to:
Show answer
Answer: B — Θ(n^{log₂3})
Here a = 3 and b = 2, so nlog_b a = nlog₂3 ≈ n1.585, which grows faster than the f(n) = n at the top level — so the leaves dominate and the answer is Θ(nlog₂3). Option A is the answer when the two are comparable, as in T(n) = 2T(n/2) + n. The reason this recurrence is worth recognising is that it is Karatsuba multiplication: three half-size multiplications instead of the naive four, which is what turns n² into n1.585 and is the whole point of the algorithm.T(n) = T(n−1) + n with T(1) = 1 solves to:
Show answer
Answer: C — Θ(n²)
Expanding gives n + (n−1) + … + 1 = n(n+1)/2 = Θ(n²). The master theorem does not apply: it requires a subproblem of size n/b, a constant fraction, whereas this reduces by a constant amount, making the recursion n deep instead of log n deep. That distinction is the whole question. It also matters practically — this is precisely the recurrence quicksort produces when every pivot is the smallest remaining element, which is what already-sorted input does to a first-element pivot, giving 4950 comparisons for n = 100.What is the minimum number of comparisons needed to find both the maximum and the minimum of 100 distinct numbers?
Numerical answer — type the value.
Show answer
Answer: 148
⌈3n/2⌉ − 2 = 150 − 2 = 148. The method is pairing: compare the 100 numbers in 50 pairs (50 comparisons), then run the 50 winners against a running maximum (49) and the 50 losers against a running minimum (49) — total 148. The naive answer 198 comes from two independent scans of n − 1 each, and it is a correct count for a worse algorithm, which is why the question asks for the minimum. This bound is tight: no method does better, and knowing that is what stops a candidate second-guessing 148 as too small.Binary search on a sorted array of 1000 elements makes how many comparisons in the worst case?
Show answer
Answer: A — 10
The worst case is ⌈log₂(n + 1)⌉ = ⌈log₂1001⌉ = 10, since each comparison halves the remaining range and 2¹⁰ = 1024 ≥ 1001. Option B is the answer for 1024 elements, where ⌈log₂1025⌉ = 11 — a one-element difference in the array producing a whole extra comparison, which is what a question exploits when it picks a size just past a power of two. The result also settles a common confusion: doubling the array adds one comparison, not double the work.Which of the following sorting algorithms have a worst-case time of Θ(n log n)? (More than one may be correct.)
Show answer
Answer: A — Merge sort; C — Heapsort
Merge sort and heapsort. Both split or sift logarithmically regardless of the input, so their worst case matches their average. Quicksort is Θ(n²) in the worst case — its O(n log n) is an average over pivot choices, and a bad pivot rule on sorted input hits the quadratic case exactly. Insertion sort is Θ(n²) too, though it is Θ(n) on nearly-sorted input, which is why it is used as the base case inside faster sorts. The distinguishing property to carry away is that heapsort achieves Θ(n log n) with Θ(1) extra space, where merge sort needs Θ(n) — that is usually the real question behind a list like this one.The Ω(n log n) lower bound for comparison sorting follows from:
Show answer
Answer: B — A decision tree needing n! leaves, so height at least log₂(n!)
Every comparison sort is a binary decision tree whose leaves are the possible answers, and there are n! orderings — so the tree needs n! leaves and therefore height at least log₂(n!) = Θ(n log n) by Stirling's approximation. That is a statement about the problem: it holds for every comparison sort that exists or ever will. Option A confuses a lower bound with an upper bound from a known algorithm, which is the conceptual error worth naming — a lower bound proved this way cannot be beaten by a better algorithm, only by changing the model, which is exactly what counting and radix sort do by not comparing at all.Counting sort runs in Θ(n + k) where k is the key range. It is a poor choice when:
Show answer
Answer: B — k is much larger than n
The Θ(k) term is the cost of the counting array, so sorting a hundred 32-bit integers means k ≈ 4 × 10⁹ and the algorithm is catastrophically worse than a comparison sort — k ≫ n is exactly the bad case. Option D is backwards: counting sort is stable, and that is one of its selling points, which is why radix sort is built on it. The general lesson is that a bound with two variables in it can only be compared against another bound once you know their relative sizes, and a question giving you k is telling you which term matters.A hash table with chaining holds n keys in m slots. Its worst-case search time is:
Show answer
Answer: B — O(n)
O(n). Nothing in the definition of a hash function stops every one of the n keys from hashing to the same slot, and then the search walks a chain of length n. Option A is the expected time under a uniform-hashing assumption, and option D is the average chain length α = n/m — both true statements about the average case, and neither is the worst case. The syllabus asks for worst-case complexity, so the distinction is not pedantry: it is why a worst-case-sensitive application uses a balanced tree at O(log n) guaranteed rather than a hash table at O(1) expected.