ETOOBUSY 🚀 minimal blogging for the impatient
Permutations with Heap's Algorithm
TL;DR
All permutations over $N$ objects can be generated by Heap’s Algorithm.
It also seems that it’s pretty good at minimizing the number of movements of stuff around.
The good thing with the current version of the Wikipedia page (as of this writing) is the pseudo-code for an iterative (i.e. non-recursive) version of the algorithm. The following is taken from there, without the comments and with variable names that are a bit more readable in my opinion:
procedure generate(n : integer, A : array of any):
stack : array of integer
sp : integer
for sp := 0; sp < n; sp += 1 do
stack[sp] := 0
end for
output(A)
sp := 0;
while sp < n do
if stack[sp] < sp then
if sp is even then
swap(A[0], A[sp])
else
swap(A[c[sp]], A[sp])
end if
output(A)
stack[sp] += 1
sp := 0
else
stack[sp] := 0
sp += 1
end if
end while
I’m particularly fond of iterative implementations, which probably makes me a bad functional programmer.
But there’s a reason for my bias, which I already talked about (I think): turning an iterative implementation into an iterator-based implementation is easier (at least for me!) and iterator-based implementations on stuff that can grow factorially can be a very, very interesting characteristic.
Here’s a corresponding Perl implementation, where we avoid taking
parameter n
explicitly and the input array is passed via @_
:
sub permutations {
my @indexes = 0 .. $#_;
my @stack = (0) x @indexes;
output(@_[@indexes]);
my $sp = 0;
while ($sp < @indexes) {
if ($stack[$sp] < $sp) {
my $other = $sp % 2 ? $stack[$sp] : 0;
@indexes[$sp, $other] = @indexes[$other, $sp];
output(@_[@indexes]);
$stack[$sp]++;
$sp = 0;
}
else {
$stack[$sp++] = 0;
}
}
}
As a matter of fact, we use array @indexes
to take the role of the
input array A
in the pseudocode, so that we avoid messing up directly
with the array.
I really like how compact this implementation is!