Store the current multiset in an unsorted prefix The loop invariant is , the complete array has its original multiset, every discarded entry on the left is at most every active entry, and every active entry is at most every discarded entry on the right. Thus the desired global order statistic is the local one of rank . The two-way array partition result either identifies it or excludes the pivot and the irrelevant side. The positive loop variant strictly decreases unless the procedure returns.
a[0..len); Add appends exactly as in part (a). The coupling invariant is equality of length and multiset with abstract xs, rather than equality of insertion order. Get applies quickselect:PROCEDURE Get(k: INTEGER): INTEGER;
VAR l, r, m: INTEGER;
BEGIN
ASSERT((0 <= k) & (k < len));
l := 0; r := len;
LOOP
m := Partition(l, r);
IF k = m THEN RETURN a[m]
ELSIF k < m THEN r := m
ELSE l := m+1
END
END
END Get;Balanced pivots give , whose geometric series is . More generally, choosing a uniformly random pivot before each call, by swapping a random active entry into
a[r-1], gives expected running time on distinct keys: with constant probability, the pivot is in the middle half and the retained side has size at most . Expected work over these shrinking stages is a convergent geometric series.The particular last-entry pivot in the displayed code has no unconditional expected guarantee without an input distribution. Its worst case repeatedly discards one entry. Duplicate keys require further care: on an all-equal segment, the strict partition always returns , so selecting the last rank costs even with randomized pivot positions. A three-way array partitioning that groups all keys equal to the pivot restores the usual randomized linear expectation with duplicates; alternatively the stated expectation assumes distinct keys. This is a qualification to the bound, not to the algorithm correctness of the displayed code.Use three-way array partitioning around a saved pivot value:
procedure Partition(var a; l, r; var m, n)
x := a[Pivot(a,l,r)]
m := l
k := l
n := r
while k < n do
if a[k] < x then
swap(a[k], a[m])
m := m+1
k := k+1
else if a[k] > x then
n := n-1
swap(a[k], a[n])
else
k := k+1Assume a total ordering on the element keys. The loop invariant partitions the original segment intowith and the segment's multiset unchanged. A smaller entry exchanges with the first equality position; the displaced equal entry is accounted for when both indices advance. A greater entry exchanges with the last unclassified position, so
k must stay to inspect the incoming entry. The loop variant decreases by one in every branch.At termination the equality interval is . It is nonempty because the pivot value came from the segment and swaps preserve the bag. The stronger strict outer-region conditions therefore imply the requested overlapping inequalities and . Storing the pivot value avoids following an array position whose contents may move.
