【发布时间】:2012-03-26 19:57:28
【问题描述】:
我对比较不同的技术/方法感兴趣,可以用来生成给定集合的所有潜在排列。
【问题讨论】:
标签: algorithm permutation
我对比较不同的技术/方法感兴趣,可以用来生成给定集合的所有潜在排列。
【问题讨论】:
标签: algorithm permutation
您可以在性能、特定分布和简单性之间进行选择。我所说的特定分布是指您是否关心输出的某些特定顺序,例如字典顺序。
据我所知,性能最好的算法是Steinhaus algorithm。从某种意义上说,它对于乘法常数是最佳的,因为生成一个排列只需要恒定数量的处理器指令(不包括打印出来所需的指令,这并不总是需要)。
还有一个非常简单的算法可以按字典顺序生成排列,您可能可以自己将其重新发明为递归过程,其性能为O(n.log(n).log( n)),因此与通过任何其他方法生成列表并对其进行排序大致相同。
编辑:这里是简单算法的伪代码:
void permute(Element[] permutationPrefix, Set rest)
{
if (rest.IsEmpty) {
// permutationPrefix is now a full permutation
print(permutationPrefix);
} else {
foreach (element in rest) {
permutationPrefix.Append(element);
permute(permutationPrefix, rest.Minus(element))
permutationPrefix.Length--; // cut away the last item
}
}
}
最初用一个空的permutationPrefix 和rest 来调用它,并持有完整的集合;如果这个集合是一个排序的数据结构,排列将按字典顺序输出。
请注意,我们在每次递归调用时复制和修改集合,这是整个算法中最昂贵的操作,可能与print 方法一起使用。单组副本的成本与排列总数成对数n;并且由于递归调用堆栈的深度也是对数,因此 O(n.log(n).log(n)) 性能估计如下。
(此算法也适用于转换为性能良好的随机排列生成器。)
【讨论】:
这个问题已经被问及回答了(事实上很多次):
Algorithm to generate all possible permutations of a list?
Permutations with a given integer
我个人认为 Steinhaus 算法对问题的思考过度:它并不比最天真的实现快多少。
最幼稚实现的类Java伪代码:
List<List<Element>> generateAllPermutations(List<Element> input)
{
List<Element> output = new ArrayList<Element>();
if (input.size() == 0)
return output;
for (Element first : input) {
for (List<Element> sequence : generateAllPermutations(input - first))
output.add(first + sequence);
}
}
【讨论】: