sub mergesort
{
@_ < 2 and return @_;
my @low = mergesort( @_[0 .. $#_ / 2] );
my @high = mergesort( @_[$#_ / 2 + 1 .. $#_] );
map !@high || @low && $low[0] <= $high[0] ? shift @low : shift @high, 1..@_;
}
####
sub sqs # stable quicksort
{
@_ < 2 and return @_;
my $p = $_[@_ / 2]; # pivot
sqs( grep $_ < $p, @_ ), grep( $_ == $p, @_ ), sqs( grep $_ > $p, @_ );
}
####
sub spsqs # single pass stable quicksort
{
@_ < 2 and return @_;
my ($pivot, @items) = ($_[@_ / 2], [], [], []);
push $items[$_ <=> $pivot]->@*, $_ for @_;
spsqs($items[-1]->@*), $items[0]->@*, spsqs($items[1]->@*)
}