Lomuto's Partition, stable or not?
I'm going to interpret "Quicksort with Lomuto's partition" as referring to the algorithm from here (slides 21–22).
This algorithm is unstable on the array [a, b, c] where c < a = b.
I found this counterexample by implementing the Quicksort algorithm in Python so that (like Python's built-in sort) it takes a key
function. By supplying an appropriate key function, I can make the sort think that certain elements are identical, but I can still distinguish them. Then it's just a matter of trying lots of permutations and spotting instability. The code below certainly doesn't exhaust the possible tests (one might want to try more than two identical elements, or multiple sets of identical elements), but it was good enough in this case.
def lomuto(A, key=lambda x:x):
def partition(A, p, r):
i = p - 1
pivot = A[r]
for j in range(p, r):
if key(A[j]) <= key(pivot):
i += 1
A[i], A[j] = A[j], A[i]
A[i+1], A[r] = A[r], A[i+1]
return i + 1
def quicksort(A, p, r):
if p < r:
q = partition(A, p, r)
quicksort(A, p, q-1)
quicksort(A, q+1, r)
quicksort(A, 0, len(A) - 1)
def test_stability(f, n):
"""Try to discover if the sorting function f is stable on n inputs;
printing the first counterexample found, if any."""
import itertools
for i in range(n - 1):
def order(P): return P.index((i, 0)) < P.index((i, 1))
array = [(j, 0) for j in range(n - 1)] + [(i, 1)]
for P in map(list, itertools.permutations(array)):
Q = P[:] # take a copy
f(Q, key=lambda x: x[0])
if order(P) != order(Q):
print(P, '->', Q)
return
>>> test_stability(lomuto, 3)
[(1, 0), (1, 1), (0, 0)] -> [(0, 0), (1, 1), (1, 0)]