啊,一旦我计算出 n=4 的序列(使用“始终将第一项与另一个交换”约束),我就能够在 OEIS 中找到序列A123400,它告诉我需要“Ehrlich 的交换方法”。
谷歌为我找到了一个 C++ 实现,我认为它在 GPL 下。我还找到了 Knuth 的分册 2b,它描述了针对我的问题的各种解决方案。
一旦我有一个经过测试的 C 实现,我将用代码更新它。
这是一些基于 Knuth 描述实现 Ehrlich 方法的 perl 代码。对于最多 10 个项目的列表,我在每种情况下都测试了它是否正确生成了完整的排列列表,然后停止了。
#
# Given a count of items in a list, returns an iterator that yields the index
# of the item with which the zeroth item should be swapped to generate a new
# permutation. Returns undef when all permutations have been generated.
#
# Assumes all items are distinct; requires a positive integer for the count.
#
sub perm_iterator {
my $n = shift;
my @b = (0 .. $n - 1);
my @c = (undef, (0) x $n);
my $k;
return sub {
$k = 1;
$c[$k++] = 0 while $c[$k] == $k;
return undef if $k == $n;
++$c[$k];
@b[1 .. $k - 1] = reverse @b[1 .. $k - 1];
return $b[$k];
};
}
示例使用:
#!/usr/bin/perl -w
use strict;
my @items = @ARGV;
my $iterator = perm_iterator(scalar @items);
print "Starting permutation: @items\n";
while (my $swap = $iterator->()) {
@items[0, $swap] = @items[$swap, 0];
print "Next permutation: @items\n";
}
print "All permutations traversed.\n";
exit 0;
根据要求,python 代码。(对不起,这可能不是过于惯用。欢迎提出改进建议。)
class ehrlich_iter:
def __init__(self, n):
self.n = n
self.b = range(0, n)
self.c = [0] * (n + 1)
def __iter__(self):
return self
def next(self):
k = 1
while self.c[k] == k:
self.c[k] = 0
k += 1
if k == self.n:
raise StopIteration
self.c[k] += 1
self.b[1:k - 1].reverse
return self.b[k]
mylist = [ 1, 2, 3, 4 ] # test it
print "Starting permutation: ", mylist
for v in ehrlich_iter(len(mylist)):
mylist[0], mylist[v] = mylist[v], mylist[0]
print "Next permutation: ", mylist
print "All permutations traversed."