没有递归的排列算法?爪哇
我想得到一个数字的所有组合,没有任何重复。 如 0.1.2、0.2.1、1.2.0、1.0.2、2.0.1、2.1.0。 我试图找到一个简单的方案,但找不到。我为它画了一个图/树,这尖叫着使用递归。 但如果可能的话,我想在不使用递归的情况下执行此操作。
谁能帮我做到这一点吗?
I would like to get all combination of a number without any repetition.
Like 0.1.2, 0.2.1, 1.2.0, 1.0.2, 2.0.1, 2.1.0.
I tried to find an easy scheme, but couldn't. I drew a graph/tree for it and this screams to use recursion.
But I would like to do this without recursion, if this is possible.
Can anyone please help me to do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
这是一个简单的 Java 函数,用于打印所有可能的排列(包括较小的排列直至空字符串“”)。如果您只需要打印相同长度的排列,只需在打印之前添加 if 语句即可。
其思想与递归相同。但不是堆叠方法调用。我们使用数据结构(如本例中的列表)来堆叠排列。
This is a simple Java function to print all possible permutations (including the smaller ones down to empty string ""). if you need to print only the same length permutations, just add if statement prior the print.
The idea is same as recursion. But instead of stacking method calls. We use a data structure (as list in this example) to stack the permutations.
您应该利用这样一个事实:当您想要 N 个数字的所有排列时,就有 N 个!可能性。因此每个数字 x 都来自 1..N!编码这样的排列。这是一个迭代打印出刺痛的所有排列的示例。
You should use the fact that when you want all permutations of N numbers there are N! possibilities. Therefore each number x from 1..N! encodes such a permutation. Here is a sample that iteratively prints out all permutations of a sting.
这是我一年前写的一个通用排列枚举器。它还可以产生“子排列”:
我的算法背后的想法是任何排列都可以表示为唯一交换命令序列。例如,对于 ,交换序列 012 将所有项目保留在原位,而 122 首先将索引 0 与索引 1 交换,然后将 1 与 2 交换,然后将 2 与 2 交换(即保留到位)。这导致了排列 BCA。
这种表示与排列表示同构(即一对一关系),并且在遍历排列空间时很容易“递增”它。对于 4 项,从 0123 (ABCD) 开始,到 3333(DABC) 结束。
Here is a generic permutation enumerator I wrote a year ago. It can also produce "sub-permutations":
The idea behind my algorithm is that any permutation can be expressed as a unique sequence of swap commands. For example, for <A,B,C>, the swap sequence 012 leaves all items in place, while 122 starts by swapping index 0 with index 1, then swaps 1 with 2, and then swaps 2 with 2 (i.e. leaves it in place). This results in the permutation BCA.
This representation is isomorphic to the permutation representation (i.e. one to one relationship), and it is very easy to "increment" it when traversing the permutations space. For 4 items, it starts from 0123 (ABCD) and ends with 3333(DABC).
一般来说,任何递归算法总是可以通过使用堆栈或队列数据结构简化为迭代算法。
对于这个特定问题,查看 C++ STL 算法
std 可能更有指导意义: :next_permutation
。根据 wordaligned.org 的 Thomas Guest 的说法,基本实现如下所示:请注意,它并不使用递归并且可以相对简单地转换为另一种类似 C 的语言(例如 Java)。您可能需要阅读 std::iter_swap、std::reverse 和 双向迭代器(
Iter
在此代码中表示的内容)。In general, any recursive algorithm can always be reduced to an iterative one through the use of stack or queue data structures.
For this particular problem, it might be more instructive to look at the C++ STL algorithm
std::next_permutation
. According to Thomas Guest at wordaligned.org, the basic implementation looks like this:Note that it does not use recursion and is relatively straightforward to translate to another C-like language like Java. You may want to read up on std::iter_swap, std::reverse, and bidirectional iterators (what
Iter
represents in this code) as well.编写递归排列很容易,但需要从深度嵌套循环中导出排列。 (这是一个有趣的练习。)我需要一个可以将字符串排列为字谜的版本。我编写了一个实现 Iterable的版本,因此它可以在 foreach 循环中使用。通过更改构造函数和属性“array”的类型,它可以轻松适应其他类型,例如
int[]
甚至泛型类型
'。It is easy to write the recursive permutation, but it requires exporting the permutations from deeply nested loops. (That is an interesting exercise.) I needed a version that permuted strings for anagrams. I wrote a version that implements
Iterable<String>
so it can be used in foreach loops. It can easily be adapted to other types such asint[]
or even a generic type<T[]>
by changing the constructor and the type of attribute 'array'.到目前为止,我见过的大多数示例要么太复杂,要么只使用字符串,要么使用交换,所以我想我应该制作一个迭代、直观、通用且无交换的示例。
示例:我们想要 [a,b,c] 的所有排列
我们添加 a 并得到 [a] // [b,c] 剩余
我们从列表中取出 a 并添加 [a,b] 和 [b,a] // [c] 剩余
我们删除 [b,a],并插入 [b,a,c]、[b,c,a]、[c,b,a],然后删除 [a,b],并插入 [a,b, c]、[a、c、b]、[c、a、b]
Most examples I've seen so far has either been too complicated, only using Strings or using swaps, so I figured I'd make one which is iterative, intuitive, generic and swap free.
Example: we want all permutations of [a,b,c]
We add a and get [a] // [b,c] remaining
We take a from the list and adds [a,b] and [b,a] // [c] remaining
We remove [b,a], and inserts [b,a,c], [b,c,a], [c,b,a] and then we remove [a,b], and inserts [a,b,c], [a,c,b], [c,a,b]
这是我根据 此处 的实现编写的通用和迭代排列、kpermutation 和组合生成器类和此处。我的类使用它们作为内部类。他们还实现了可迭代接口。
Combinations 类:
Permutations 类:
以及实际使用 Permutations 和 Combinations 类的 KPermutations 类:
Here is the generic and iterative permutation, kpermutation and combination generator classes that I wrote based on the implementations here and here. My classes use those as inner classes. They also implement Iterable Interface to be foreachable.
The Combinations class:
The Permutations Class:
And the KPermutations class that actually using Permutations and Combinations classes:
这里我有一个scala解决方案,它可以从java中使用,但可以通过更多代码来实现在 Java 中,也允许使用迭代器来简化 for 循环:
为了简化for循环,我们需要实现Iterable,这意味着我们必须提供一个返回Iterator的方法,而Iterator恰好是另一个接口,这意味着我们必须实现3个方法: hasNext();下一个 ();并删除 ();
PermutationIterator 包含附加的公共方法
public List; get (final int code)
如果您想通过索引(例如随机)选择某个排列,这会很方便。您知道大小(最后一个),因此可以按索引对有效范围进行排列。PermutationIterable 包含一个“invers”方法,它将生成相反的结果:某个排列的索引。
在内部,invers 和 get 递归地工作,但所有排列都不是递归生成的,因此即使对于大排列,这也不应该成为问题。请注意,对于 21 个元素,您超出了 long 的大小,并且 20 步递归根本不应该成为问题。
Here I have a solution in scala, which could be used from java, but can be - with much more code - been implemented in Java as well, to allow to use an iterator for the simplified for-loop:
To allow for the simplified for-loop, we need to implement Iterable, which means we have to provide a method which returns an Iterator, which happens to be another interface, which means we have to implement 3 methods: hasNext (); next (); and remove ();
PermutationIterator contains the additional, public method
public List <T> get (final int code)
which is handy, if you like to pick a certain permutation by index, for example by random. You know the size (last) and can therefore take a permutation of the valid range by index.PermutationIterable contains a method 'invers' which will generate the opposite: The index of a certain permutation.
Internally, invers and get work recursively, but all the permutations aren't produced recursively, so this shouldn't be a problem even for big permutations. Note, that for 21 elements, you exceed the size of longs, and 20 steps of recursion shouldn't be a problem at all.
您可以使用 Factoradics (您可以看到一个实现此处) 或 Knuth 的 L 算法,生成所有排列。下面是后者的实现:
You can use Factoradics (you can see an implementation here) or the Knuth's L-Algorithm that generates all permutations. The following is an implementation of the latter:
这当然以前已经做过,一种解决方案是贝尔排列算法。
您可以在此处找到一个解决方案,在这里您可以找到 Prolog 中的递归解决方案和非递归贝尔排列用 Pascal 编写的算法。
将它们转换为 Java 留给读者作为练习。
This has of course been done before, and one sollution is Bells Permutation Algorithm.
You find a sollution here, where you can find a recursive sollution in Prolog and the non-recursive Bell Permutation Algorithm written in Pascal.
To convert them to Java is left as an exercise for the reader.
@Filip Nyugen JS 解决方案,适合那些想要 JS 答案的人
@Filip Nyugen solution in JS for those of you who want the answer in JS