Sorting algorithms/Quicksort: Difference between revisions

Content added Content deleted
imported>Rcmlz
imported>Rcmlz
Line 8,228: Line 8,228:
=={{header|Raku}}==
=={{header|Raku}}==
(formerly Perl 6)
(formerly Perl 6)
<syntaxhighlight lang="raku" line># Empty list sorts to the empty list
<syntaxhighlight lang="raku" line>
multi quicksort([]) { () }
#| Recursive, quicksort implementation
multi quicksort(@unsorted where @unsorted.elems < 2) { @unsorted }
multi quicksort(@unsorted) {
# Otherwise, extract first item as pivot...
my $pivot = @unsorted.pick;
multi quicksort([$pivot, *@rest]) {
my %class{Order} is default([]);
# Partition.
my $before := @rest.grep(* before $pivot);
%class = @unsorted.classify: * cmp $pivot;
|quicksort(%class{Less}), |%class{Same}, |quicksort(%class{More})
my $equiv := @rest.grep(* eqv $pivot);
}
my $after := @rest.grep(* after $pivot);
</syntaxhighlight>


The partitions can be sorted in parallel.
# Sort the partitions.
flat quicksort($before), $pivot, $equiv, quicksort($after)
}</syntaxhighlight>
Note that <code>$before</code> and <code>$after</code> are bound to lazy lists. The partitions can be sorted in parallel.


<syntaxhighlight lang="raku" line>
<syntaxhighlight lang="raku" line>
#|« Recursive, concurrent quicksort implementation
#| Recursive, parallel, quicksort implementation
multi quicksort-parallel(@unsorted where @unsorted.elems < 2) { @unsorted }

multi quicksort-parallel(@unsorted) {
* in partitioning/classifying step by .race or .hyper
my %class{Order} is default([]);
* in recursion step on Less partition by start {}
my $pivot = @unsorted.pick;
»
%class = @unsorted.classify( * cmp $pivot );
sub quicksort-recursive-concurrent(@input) {
my $less = start { samewith(%class{Less}) };
return @input if @input.elems < 2;
my $pivot = @input.pick;
my $more = samewith(%class{More});
await $less andthen |$less.result, |%class{Same}, |$more
@input.race.classify( * cmp $pivot )
andthen
{
my %partiton = $_;
my $less = start { %partiton{Less}:exists ?? samewith(%partiton{Less}) !! [] };
my $more = %partiton{More}:exists ?? samewith(%partiton{More}) !! [];
await $less andthen |$less.result, |%partiton{Same}, |$more
}
}
}
#=« Implementation Notes:
#=« Implementation Notes:
* no need to start a new thread for More partition - as we better use current thread.
* use the current thread for More partition
* recursion on Less partition can create a large number of new threads
* hyper/race using default batch=64 and degree=4 -> tune it!
* samewith() refactors out the actual name of the routine.
* recursion on the Less partition can create a large number of new threads -> limit it!
* samewith() refactors out the actual name of the routine.
* andthen passes the result of the previous block as $_ to the next block.
»
»
</syntaxhighlight>
</syntaxhighlight>
Line 8,283: Line 8,272:
<a 🎮 3 z 4 🐧> => <a 🎮 3 z 4 🐧>.sort,
<a 🎮 3 z 4 🐧> => <a 🎮 3 z 4 🐧>.sort,
;
;
for &quicksort, &quicksort-recursive-parallel -> &fun {
for &quicksort, &quicksort-parallel -> &fun {
say &fun.name;
is-deeply &fun(.key), .value, .key ~ "\t->\t" ~ .value for @testcases;
is-deeply &fun(.key), .value, .key ~ " => " ~ .value for @testcases;
}
}
</syntaxhighlight>
</syntaxhighlight>
<pre>
quicksort
ok 1 - =>
ok 2 - a => a
ok 3 - a a => a a
ok 4 - a b => a b
ok 5 - b a => a b
ok 6 - h b a c d f e g => a b c d e f g h
ok 7 - 2 3 1 4 5 => 1 2 3 4 5
ok 8 - a 🎮 3 z 4 🐧 => 3 4 a z 🎮 🐧
quicksort-parallel
ok 9 - =>
ok 10 - a => a
ok 11 - a a => a a
ok 12 - a b => a b
ok 13 - b a => a b
ok 14 - h b a c d f e g => a b c d e f g h
ok 15 - 2 3 1 4 5 => 1 2 3 4 5
ok 16 - a 🎮 3 z 4 🐧 => 3 4 a z 🎮 🐧
</pre>


=={{header|Red}}==
=={{header|Red}}==