Given the mess that is
Re: Challenge: Sorting Sums Of Sorted Series, I'll post a pair of working, fast solutions here. The solutions that follow use O(N+M) memory and are O(N^2*M) in time. The basic algorithm implemented is:
Populate a queue with the sum of all elements of the short list with the first element of the other list. Keep track of the indices of each value. This queue is by definition sorted. Then loop until the queue is empty, doing the following:
- Shift and print the first element of the queue;
- Increment the second list index for the shifted element. Cycle loop if this index is outside the second list.
- Use a sorted insertion to add the sum at the new coordinates to the queue.
I wrote a version with an array for each tracked element (solution_2) and one where all three are lumped into a single entry.
sub solution_2 {
# adaptive motion queue solution
my ($list_ref1, $list_ref2) = @_;
my @list1;
my @list2;
if (@$list_ref1 <= @$list_ref2) {
@list1 = @$list_ref1;
@list2 = @$list_ref2;
} else {
@list1 = @$list_ref2;
@list2 = @$list_ref1;
}
my @queue = map $_+$list2[0], @list1;
my @xs = (0 .. $#list1);
my @ys = (0) x @list1;
while (@queue) {
print OUT shift(@queue), "\n";
my $x = shift @xs;
my $y = shift @ys;
next if ++$y >= @list2;
my $sum = $list1[$x] + $list2[$y];
my $count = 0;
$count++ until $count == @queue or $sum <= $queue[$count];
splice @queue, $count, 0, $sum;
splice @xs, $count, 0, $x;
splice @ys, $count, 0, $y;
}
}
sub solution_3 {
# adaptive motion queue solution, one array
my ($list_ref1, $list_ref2) = @_;
my @list1;
my @list2;
if (@$list_ref1 <= @$list_ref2) {
@list1 = @$list_ref1;
@list2 = @$list_ref2;
} else {
@list1 = @$list_ref2;
@list2 = @$list_ref1;
}
my @queue = ();
for (0 .. $#list1) {
push @queue, join("x", $list1[$_]+$list2[0], "$_", "0");
}
while (@queue) {
my $entry = shift(@queue);
my ($old, $x, $y) = split /x/, $entry;
print OUT "$old\n";
next if ++$y >= @list2;
my $sum = $list1[$x] + $list2[$y];
my $count = 0;
{
no warnings 'numeric';
$count++ until $count == @queue or $sum <= $queue[$count];
}
splice @queue, $count, 0, "${sum}x${x}x${y}";
}
}
And benchmarks on 4 element and 100 element equally distributed arrays:
Benchmark: timing 100 iterations of 1_array, 3_array, Baseline, LR_1..
+.
1_array: 10.651 wallclock secs (10.65 usr + 0.00 sys = 10.65 CPU)
+@ 9.39/s (n=100)
3_array: 9.28456 wallclock secs ( 9.28 usr + 0.00 sys = 9.28 CPU)
+ @ 10.78/s (n=100)
Baseline: 0.844141 wallclock secs ( 0.84 usr + 0.00 sys = 0.84 CPU
+) @ 119.05/s (n=100)
(warning: too few iterations for a reliable count)
LR_1: 20.4537 wallclock secs (20.45 usr + 0.00 sys = 20.45 CPU)
+ @ 4.89/s (n=100)
Rate LR_1 1_array 3_array Baseline
LR_1 4.89/s -- -48% -55% -96%
1_array 9.39/s 92% -- -13% -92%
3_array 10.8/s 120% 15% -- -91%
Baseline 119/s 2335% 1168% 1005% --
Benchmark: timing 100000 iterations of 1_array, 3_array, Baseline, LR_
+1...
1_array: 7.06968 wallclock secs ( 7.07 usr + 0.00 sys = 7.07 CPU)
+ @ 14144.27/s (n=100000)
3_array: 5.09259 wallclock secs ( 5.09 usr + 0.00 sys = 5.09 CPU)
+ @ 19646.37/s (n=100000)
Baseline: 2.11864 wallclock secs ( 2.12 usr + 0.00 sys = 2.12 CPU)
+ @ 47169.81/s (n=100000)
LR_1: 7.01637 wallclock secs ( 7.02 usr + 0.00 sys = 7.02 CPU)
+ @ 14245.01/s (n=100000)
Rate 1_array LR_1 3_array Baseline
1_array 14144/s -- -1% -28% -70%
LR_1 14245/s 1% -- -27% -70%
3_array 19646/s 39% 38% -- -58%
Baseline 47170/s 233% 231% 140% --
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.