Here is my attempt:
fun swap(A,i,j) =
let
val t = Array.sub(A,i)
in
Array.update(A,i,Array.sub(A,j));
Array.update(A,j,t)
end
fun firstAfter(A,i,f) =
if f(Array.sub(A,i)) then i else firstAfter(A,i+1,f)
fun lastBefore(A,j,f) =
if f(Array.sub(A,j)) then j else lastBefore(A,j-1,f)
fun partition(A,lo,hi)=
let
fun partition'(A,lo,hi,pivot) =
let
val i = firstAfter(A,lo,fn k => k >= pivot)
val j = lastBefore(A,hi,fn k => k <= pivot)
in
if i >= j then
j
else
(
swap(A,i,j);
partition'(A,i+1,j-1,pivot)
)
end
in
partition'(A,lo,hi,Array.sub(A,lo))
end
fun quicksort(A,lo,hi) =
if hi <= lo then
()
else
let
val p = partition(A,lo,hi)
in
(
quicksort(A,lo,p);
quicksort(A,p+1,hi)
)
end;
fun qsort A = quicksort(A,0,Array.length A - 1);
It follows Hoare's algorithm as described in Wikipedia fairly closely but uses recursion rather than loops, and has a somewhat functional approach for looking for pairs of indices to swap. There is no question that this is nowhere nearly as elegant as the 2 or 3 line pseudo-quicksort which is often taught in introductory treatments of functional programming and it doesn't really showcase the powers of functional programming. Hopefully someone who knows more SML than I can come up with a more idiomatic SML qsort.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…