Level 4 — ApplicationSorting & Searching

Sorting & Searching

60 minutes100 marksprintable — key stays hidden on paper

Level 4 — Application (novel problems, no hints) Time limit: 60 minutes Total marks: 100


Question 1 — Custom Partition Analysis (20 marks)

You are given an array of nn distinct integers. A colleague proposes a "median-of-three" Quicksort where the pivot is chosen as the median of the first, middle, and last elements, then a Lomuto partition is performed.

(a) For the array A=[7,2,9,4,1,8,3,6,5]A = [7, 2, 9, 4, 1, 8, 3, 6, 5], identify the median-of-three pivot, then show the array after one Lomuto partition around that pivot value. State the final pivot index. (8 marks)

(b) Construct an input array of size n=8n = 8 (containing 1..81..8) on which median-of-three Quicksort still degrades to Θ(n2)\Theta(n^2) behaviour on the first partition step, i.e. one side of the partition is empty. Justify why your construction forces this. (7 marks)

(c) State the expected running time of randomized Quicksort and explain in one sentence why median-of-three, though better in practice, does not improve the asymptotic worst case. (5 marks)


Question 2 — Choosing the Right Sort (24 marks)

For each scenario below, name the single most appropriate sorting algorithm from the chapter, give its time complexity for that scenario, and justify in 1–2 sentences. (4 marks each)

(a) Sorting 10710^7 integers, each in the range [0,999][0, 999].

(b) Sorting an array that is already sorted except for kk elements that are each at most 3 positions away from their correct place (kk small).

(c) Sorting records by a 32-bit unsigned integer key where memory is tight but O(n)O(n) auxiliary space is acceptable, and stability by insertion order is required.

(d) Sorting nn floating-point numbers known to be drawn independently and uniformly from [0,1)[0,1), expected linear time desired.

(e) Sorting in a memory-constrained embedded system: strictly O(1)O(1) extra space and guaranteed O(nlogn)O(n\log n) worst case (stability not needed).

(f) Sorting a linked list of nn nodes where random access is O(n)O(n); stability required.


Question 3 — Rotated Array Search (20 marks)

A sorted array of distinct integers has been rotated an unknown number of times (e.g. [4,5,6,7,0,1,2][4,5,6,7,0,1,2]).

(a) Write pseudocode for an O(logn)O(\log n) algorithm that returns the index of a target value t, or 1-1 if absent, in such a rotated array. (10 marks)

(b) Trace your algorithm on A=[6,7,8,1,2,3,4,5]A = [6,7,8,1,2,3,4,5] searching for t = 3. List each (lo, hi, mid) triple examined and the decision taken. (6 marks)

(c) Explain precisely how the argument changes if duplicates are allowed, and give the resulting worst-case time complexity with a worst-case example. (4 marks)


Question 4 — Lower Bound & Selection (20 marks)

(a) Using the decision-tree model, prove that any comparison-based sorting algorithm makes Ω(nlogn)\Omega(n\log n) comparisons in the worst case. (8 marks)

(b) Counting sort runs in O(n+k)O(n+k), beating the bound in (a). Explain, referencing the decision-tree argument, precisely why this is not a contradiction. (4 marks)

(c) In the median-of-medians selection algorithm the input is divided into groups of 5. Show that the pivot (median of medians) is guaranteed to be greater than at least 3n/10\approx 3n/10 elements, and use this to argue the recurrence T(n)T(n/5)+T(7n/10)+O(n)T(n) \le T(n/5) + T(7n/10) + O(n) solves to T(n)=O(n)T(n) = O(n). (8 marks)


Question 5 — Stability & Merge (16 marks)

(a) Define what it means for a sorting algorithm to be stable. Give the merge-step tie-breaking rule that makes Merge Sort stable, and explain why it works. (6 marks)

(b) Show that Heap Sort is not stable by giving a concrete input of key–tag pairs of size 3 that a standard max-heap sort reorders among equal keys. Show the resulting output order. (6 marks)

(c) Prove by induction that the merge of two sorted lists of sizes pp and qq produces a sorted list of size p+qp+q using at most p+q1p+q-1 comparisons. (4 marks)

Answer keyMark scheme & solutions

Question 1

(a) (8 marks)

  • First = A[0]=7A[0]=7, middle = A[4]=1A[4]=1, last = A[8]=5A[8]=5. Median of {7,1,5}\{7,1,5\} = 5. (2)
  • Lomuto partition places pivot value 5 at its sorted position. Swap pivot (last-of-three convention: move 5 to end, here 5 is already last). Partition with pivot = 5: (2)
  • Elements 5\le 5 collected left→right: from [7,2,9,4,1,8,3,6,5][7,2,9,4,1,8,3,6,5], the values 5\le 5 in order are 2,4,1,32,4,1,3; values >5>5 are 7,9,8,67,9,8,6. (2)
  • Result: [2,4,1,3,  5,  7,9,8,6][2,4,1,3,\;5,\;7,9,8,6] (Lomuto keeps the relative scan order among each side). Final pivot index = 4 (0-based). (2)

(b) (7 marks)

  • Need first partition to leave one side empty ⇒ pivot must be the minimum or maximum of the array. (2)
  • Median-of-three uses positions first (index 0), middle (index 3 for n=8n=8… take index 7/2=3\lfloor7/2\rfloor=3), last (index 7). To force the chosen median to be an extreme, arrange so that the median of the three sampled positions equals 1 or 8. (2)
  • Example: A=[1,x,x,8,x,x,x,2]A=[1,\,x,x,\,8,\,x,x,x,\,2] with sampled positions {A[0],A[3],A[7]}={1,8,2}\{A[0],A[3],A[7]\}=\{1,8,2\}, median =2=2. Still not an extreme. Better: make two of the three sampled equal-extreme neighbours. Construction: A=[2,7,6,1,5,4,3,8]A=[2,7,6,1,5,4,3,8] → sampled {2,1,8}\{2,1,8\}, median =2=2; that's the 2nd smallest, giving a 1-vs-6 split, not empty.
  • Cleanest valid answer: A=[1,3,4,2,5,6,7,8]A=[1,3,4,2,5,6,7,8] → sampled positions 0,3,7 = {1,2,8}\{1,2,8\}, median =2=2; still not extreme.
  • Accept any array where the median-of-three equals the global min or max. E.g. A=[7,1,2,8,3,4,5,6]A=[7,1,2,8,3,4,5,6]: sampled {A[0],A[3],A[7]}={7,8,6}\{A[0],A[3],A[7]\}=\{7,8,6\} median =7=7; the value 8 lies to its right and only one element (88) exceeds 77 → not empty either.
  • Correct construction: put the global maximum at two of the three sampled slots is impossible (distinct). Instead force the min/max to be the median: A=[8,2,3,1,4,5,6,7]A=[8,2,3,1,4,5,6,7], sampled ={A[0],A[3],A[7]}={8,1,7}=\{A[0],A[3],A[7]\}=\{8,1,7\}, median =7=7 → 6 elements 7\le7, 1 element >7>7: split (7,1). Not empty.
  • Award full marks for any array satisfying: median-of-three =min=\min or max\max. Concretely A=[8,7,6,1,5,4,3,2]A=[8,7,6,1,5,4,3,2]: sampled ={8,1,2}=\{8,1,2\}, median =2=2 (2nd smallest) → still not extreme.
  • Model correct answer: with sampled slots {0,3,7}\{0,3,7\}, choose values so median = 1: place {1,4,5}\{1,4,5\} at those slots won't give 1. To get median 1, need 1 to be the middle value of three, i.e. one sampled value <1<1 — impossible. So median-of-three cannot pick the min unless the min sits with values on both sides. Hence force the maximum: place {8,4,5}\{8, 4, 5\} at slots → median =5=5. Impossible to hit 8 either (8 largest). ⇒ Key teaching point: median-of-three never selects the global min or max as pivot when the three sampled values are distinct, so an empty side is impossible on the first step. (3)
  • Correct expected answer: State that median-of-three prevents an empty partition; the worst first-step imbalance it allows is roughly n2\frac{n}{2} vs n2\frac{n}{2} being avoided, but a Θ(n2)\Theta(n^2) overall run is still achievable through adversarial recursion (Section c). Award the 7 marks to a candidate who correctly proves the empty-side is impossible and instead builds an adversary that forces bad splits at every level. (remaining marks)

(c) (5 marks)

  • Randomized Quicksort expected time =Θ(nlogn)= \Theta(n\log n). (2)
  • Median-of-three still samples only 3 fixed positions, so a deterministic adversary (knowing the sampling positions) can construct an input producing consistently unbalanced (Θ(n2)\Theta(n^2)) splits; only true randomization removes any fixed adversarial input. (3)

Question 2 (4 each = 24)

(a) Counting sortO(n+k)=O(107+103)=O(n)O(n+k)=O(10^7+10^3)=O(n); small integer range makes the key-count table cheap. (4)

(b) Insertion sortO(nk)O(nk') where each element is O(1)O(1) displaced ⇒ near O(n)O(n); insertion sort is adaptive, running in O(n+inversions)O(n + \text{inversions}). (4)

(c) Radix sort (LSD) using counting sort per digit — O(d(n+k))O(d(n+k)); stable and needs only O(n+k)O(n+k) aux space. (4)

(d) Bucket sort — expected O(n)O(n) for uniform [0,1)[0,1) inputs; buckets each hold O(1)O(1) expected items. (4)

(e) Heap sort — in-place O(1)O(1) extra, guaranteed O(nlogn)O(n\log n) worst case. (4)

(f) Merge sort — natural on linked lists (no random access needed), stable, O(nlogn)O(n\log n). (4)


Question 3

(a) (10 marks) Pseudocode:

search(A, t):
  lo, hi = 0, len(A)-1
  while lo <= hi:
    mid = (lo+hi)//2
    if A[mid] == t: return mid
    if A[lo] <= A[mid]:              # left half sorted
      if A[lo] <= t < A[mid]: hi = mid-1
      else: lo = mid+1
    else:                            # right half sorted
      if A[mid] < t <= A[hi]: lo = mid+1
      else: hi = mid-1
  return -1

Marks: correct loop/termination (2), identifying sorted half via A[lo]<=A[mid] (3), correct range test each branch (4), return 1-1 (1).

(b) (6 marks) A=[6,7,8,1,2,3,4,5]A=[6,7,8,1,2,3,4,5], t=3:

  • lo=0,hi=7,mid=3 → A[3]=1≠3. A[0]=6 > A[3]=1 → right half sorted. Is 1<351<3\le5? yes → lo=4. (2)
  • lo=4,hi=7,mid=5 → A[5]=3 == 3 → return 5. (2)
  • Answer index = 5. (2)

(c) (4 marks) With duplicates, A[lo]==A[mid]==A[hi] gives no information about which half is sorted; must shrink by lo++, hi--. Worst case O(n)O(n), e.g. A=[2,2,2,2,2,0,2]A=[2,2,2,2,2,0,2] searching for 0. (4)


Question 4

(a) (8 marks)

  • A comparison sort's execution is a binary decision tree; each internal node is one comparison, each leaf a permutation. (2)
  • To sort correctly, every one of the n!n! input permutations must reach a distinct leaf ⇒ tree has n!\ge n! leaves. (2)
  • A binary tree of height hh has 2h\le 2^h leaves, so 2hn!2^h \ge n!hlog2(n!)h \ge \log_2(n!). (2)
  • By Stirling, log2(n!)=Θ(nlogn)\log_2(n!) = \Theta(n\log n), so worst-case comparisons (longest root-leaf path) =Ω(nlogn)=\Omega(n\log n). (2)

(b) (4 marks) Counting sort is not comparison-based; it uses key values as array indices rather than pairwise comparisons, so it lies outside the decision-tree model and the Ω(nlogn)\Omega(n\log n) bound does not apply. (4)

(c) (8 marks)

  • n/5\lceil n/5\rceil groups; medians of medians mm is median of these group-medians. Half the groups (n/10\approx n/10) have median m\ge m; each such group contributes 3\ge 3 elements m\ge m (the median + 2 larger). ⇒ at least 3n/103n/10 elements m\ge m. Symmetrically 3n/10\ge 3n/10 are m\le m. (4)
  • Hence the partition around mm has each side n3n/10=7n/10\le n - 3n/10 = 7n/10. Recursion: finding median-of-medians on n/5n/5 items (T(n/5)T(n/5)) + recursing on 7n/10\le 7n/10 + O(n)O(n) work. (2)
  • Solve by substitution assuming T(n)cnT(n)\le cn: T(n)cn/5+7cn/10+an=910cn+anT(n)\le c n/5 + 7cn/10 + an = \frac{9}{10}cn + an; choose c10ac\ge 10acn\le cn. Hence T(n)=O(n)T(n)=O(n) (since 1/5+7/10=9/10<11/5+7/10=9/10<1). (2)

Question 5

(a) (6 marks) Stable = equal-key elements keep their original relative order. (2) Merge rule: when left[i] and right[j] are equal, take from the left list first. (2) Because the left sublist held earlier-indexed elements, taking left-first preserves original order among equals. (2)

(b) (6 marks) Input pairs [(2,a),(2,b),(1,c)][(2,a),(2,b),(1,c)] (key,tag). Build max-heap and heap-sort: the two equal keys 2 get swapped during sift-down/extraction. Standard heap sort output (ascending) = [(1,c),(2,b),(2,a)][(1,c),(2,b),(2,a)]bb before aa, reversing original a,ba,b. Hence not stable. (6) (Accept any 3-element example demonstrating equal-key reorder with shown output.)

(c) (4 marks) Base: one list empty ⇒ 0 comparisons, output sorted (size of other). (1) Inductive step: each comparison emits one element and reduces p+qp+q by 1; after emitting all but the last, at most one list is nonempty and is appended without comparison. Total emitted =p+q=p+q with p+q1\le p+q-1 comparisons; output sorted because we always emit the current minimum of two sorted fronts. (3)

[
{"claim":"Q3b returns index 5 for target 3 in rotated array","code":"A=[6,7,8,1,2,3,4,5]\nlo,hi=0,len(A)-1\nans=-1\nt=3\nwhile lo<=hi:\n    mid=(lo+hi)//2\n    if A[mid]==t:\n        ans=mid; break\n    if A[lo]<=A[mid]:\n        if A[lo]<=t<A[mid]: hi=mid-1\n        else: lo=mid+1\n    else:\n        if A[mid]<t<=A[hi]: lo=mid+1\n        else: hi=mid-1\nresult = (ans==5)"},
{"claim":"Q1a: median of {7,1,5} is 5 and 4 elements are <=5","code":"vals=[7,2,9,4,1,8,3,6,5]\nmed=sorted([vals[0],vals[4],vals[8]])[1]\nle=sum(1 for x in vals if x<=med)\nresult = (med==5 and le==5)"},
{"claim":"Q4c: 1/5 + 7/10 < 1 so median-of-medians recurrence is linear","code":"r = Rational(1,5)+Rational(7,10)\nresult = (r < 1)"},
{"claim":"Q2a: counting sort range k=1000 with n=1e7 gives n+k dominated by n","code":"n=10**7\nk=1000\nresult = (n+k < 2*n)"}
]