$ perl -w permute_n.pl 3 0: 1,2,3 1: 1,3,2 2: 2,1,3 3: 2,3,1 4: 3,1,2 5: 3,2,1 #### $ perl -w permute_n.pl 18 0 2 4 -5 -3 -1 0: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18 2: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,17,16,18 4: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,18,16,17 6402373705727995: 18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,1,3,2 6402373705727997: 18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,2,3,1 6402373705727999: 18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1 #### #!/usr/bin/perl # # demo application for 'generate the n_th permutation of a list' # # permute_n [set_size [permutation_numbers]] # # parameters: # set_size # sets the size of the set to be used for permutation generation. # The set is built from numbers starting at 1. # # permutation_number # selects the permutation to be generated. # Negative values select from the end. # # defaults are: # set size=4 # (none)=generate all permutations # # The algorithm allows for 'random-access' generation of permutations. # In order to generate the last permutation, it is NOT necessary # to cycle through all preceeding permutations. # # (c) Heiko Eißfeldt, 2008 # use strict; use integer; use warnings; use bigint; my @object; my $size = shift || 4; my @perms = @ARGV; my $last = factorial($size); if (defined $perms[0]) { for my $n (@perms) { if ($n < 0) { $n += $last; } @object = (1..$size); permute_n($n, \@object); } } else { for my $which_permutation (0 .. $last - 1) { @object = (1..$size); permute_n($which_permutation, \@object); } } sub permute_n { my ($which_permutation, $object_ref) = @_; my $size = scalar @{$object_ref}; my $current_fac = factorial($size - 1); my $perm = $which_permutation; for my $level (reverse 2..$size) { my $offset = $size - $level; my $to_front = $perm / $current_fac; $perm = $perm % $current_fac; $current_fac = $current_fac / ($level-1); next if ($to_front == 0); # move position to front @{$object_ref}[$offset..$size-1] = ($object_ref->[$offset+$to_front], @{$object_ref}[$offset .. $offset+$to_front-1], @{$object_ref}[$offset+$to_front+1 .. $size-1], ); } print "$which_permutation: ", join(q{,}, @{$object_ref}), "\n" or die "print $!\n"; return; } sub factorial { my ($n) = @_; my $result = 1; for my $fac (2..$n) { $result *= $fac; } return $result; }