First pass at a simple (i.e., non-optimal) quicksort function implemented in coffeescript.
Notably, does not sort in-place and is less than optimal in runtime because of its choice of pivot element (viz., the first element).
A very naive version of quicksort might look as follows:
qsort = ([p, rest...]) ->
return [] unless x?
lt = (x for x in rest when x <= p)
gt = (x for x in rest when x > p)
qsort(lt)
.concat(x)
.concat(qsort(gt))
This is nice and compact, but we’re iterating over the input array (minus its first element p
) twice. So, in lieu of the double list comprehensions, we’re going to reduce
the array to a partition object (part
) with less-than (lt
) and greater-than (gt
) properties.
We first create a function for creating a partition iterator. We’ll use this
to reduce the input to a partition object. This contains the items less than
or equal to p
(viz. part.lt
) and those greater than p
(part.gt
). The
resulting partition object will have the following form:
part =
lt: [ input items <= p ]
gt: [ input items > p ]
The following returns an iterator that takes a partition object part
for its initial value / previous value / accumulator. The returned partition should be partitioned at p
.
partitionAt = (p) ->
(part, x) ->
if x > p then part.gt.push(x) else part.lt.push(x)
part
Initial partition object:
init = ->
lt: []
gt: []
Our simple quicksort routine:
qsort = ([x, xs...]) ->
return [] unless x?
part = xs.reduce(partitionAt(x), init())
qsort(part.lt)
.concat(x)
.concat(qsort(part.gt))
Testing:
{ok, deepEqual} = require 'assert'
eq = deepEqual
input = [3, 2, 1, 3, 4, 6, 5]
expected = [1, 2, 3, 3, 4, 5, 6]
eq qsort(input), expected