【发布时间】:2009-10-31 05:23:53
【问题描述】:
有人可以解释一个好的算法来以有效的方式找到给定数字集的所有排列吗?
【问题讨论】:
-
我想还是保留这个比较好。
标签: c# .net permutation
有人可以解释一个好的算法来以有效的方式找到给定数字集的所有排列吗?
【问题讨论】:
标签: c# .net permutation
最简单的方法是递归方法,即在可执行伪代码中;
def permute(theseq):
if len(theseq) <= 1:
yield theseq
return
for i in range(len(theseq)):
theseq[0], theseq[i] = theseq[i], theseq[0]
for subperm in permute(theseq[1:]):
yield theseq[:1] + subperm
theseq[0], theseq[i] = theseq[i], theseq[0]
如果您不熟悉 executable pseudocode,符号 [1:] 和 [:1] 表示“切片”(分别为“除第一个之外的所有切片”和“仅第一个切片”),而这两个相同的分配执行“交换第 0 和第 i 个项目”和“将它们放回原处”的任务(即再次交换它们;-)。 yield 表示“提供此结果,但在迭代时准备好继续”,而 return 表示“我们都完成了,再见!”。
沿着不同的性能轴有一些更好的方法,但第一个里程碑是确保您完全熟悉基本的递归方法并彻底理解它 - 所以我现在就在这里停下来。如果并且当您完全理解这种方法时,为什么它工作得很好而且花花公子,和如何以及为什么它在性能上看起来并不是最佳的,我会很高兴 扩展这个答案!-)
【讨论】:
我对 Alex 的伪代码的 c# 实现:
private int length;
private List<List<string>> permutations;
public List<List<string>> Generate(List<string> list)
{
length = list.Count;
permutations = new List<List<string>>();
foreach(List<string> subperms in Recursive(list))
permutations.Add(subperms);
return permutations;
}
private List<List<string>> Recursive(List<string> list)
{
List<List<string>> subperms = new List<List<string>>();
if (list.Count <= 1)
{
subperms.Add(list);
return subperms;
}
for (int i = 0; i < list.Count; i++)
{
string temp = list[0];
list[0] = list[i];
list[i] = temp;
List<string> tail = new List<string>(list);
tail.RemoveAt(0);
List<string> head = new List<string>();
head.Add(list[0]);
foreach (List<string> subperm in Recursive(tail))
{
List<string> headCopy = new List<string>(head);
headCopy.AddRange(subperm);
if (headCopy.Count == length)
permutations.Add(headCopy);
else
subperms.Add(headCopy);
}
temp = list[0];
list[0] = list[i];
list[i] = temp;
}
return subperms;
}
【讨论】:
您看过 Knuth 的“计算机编程艺术”吗?第 3 卷,排序和搜索涵盖了它,这是有道理的,因为排序会创建数据的特定排列。
警惕能够找到所有组合或排列的组合(和排列)算法。它们的 Big-O 符号成本非常昂贵。
【讨论】: