Ở đây tôi có a solution in scala, mà có thể được sử dụng từ java, nhưng có thể - với mã nhiều hơn nữa - được thực hiện trong Java là tốt, để cho phép sử dụng một iterator cho đơn giản cho vòng lặp:
for (List<Integer> list: permutations)
doSomething (list);
Để cho phép vòng lặp đơn giản hóa, chúng ta cần thực thi Iterable, có nghĩa là chúng ta phải cung cấp một phương thức trả về một Iterator, một giao diện khác, có nghĩa là chúng ta phải thực hiện 3 phương thức: hasNext(); kế tiếp(); và xóa();
import java.util.*;
class PermutationIterator <T> implements Iterator <List <T>> {
private int current = 0;
private final List <T> lilio;
public final long last;
public PermutationIterator (final List <T> llo) {
lilio = llo;
long product = 1;
for (long p = 1; p <= llo.size(); ++p)
product *= p;
last = product;
}
public boolean hasNext() {
return current != last;
}
public List <T> next() {
++current;
return get (current - 1, lilio);
}
public void remove() {
++current;
}
private long fac (long l)
{
for (long i = l - 1L; i > 1L; --i)
l *= i;
return l;
}
/**
new version, which produces permutations in increasing order:
*/
private List <T> get (final long code, final List <T> list) {
if (list.isEmpty())
return list;
else
{
int len = list.size(); // len = 4
long max = fac (len); // max = 24
long divisor = max/len; // divisor = 6
int i = (int) (code/divisor); // i = 2
List <T> second = new ArrayList <T> (list.size());
second.addAll (list);
T el = second.remove (i);
List <T> tt = new ArrayList <T>();
tt.add (el);
tt.addAll (get (code - divisor * i, second));
return tt;
}
}
public List <T> get (final int code)
{
return get (code, lilio);
}
}
class PermutationIterable <T> implements Iterable <List <T>> {
private List <T> lilio;
public PermutationIterable (List <T> llo) {
lilio = llo;
}
public Iterator <List <T>> iterator() {
return new PermutationIterator <T> (lilio);
}
private long invers (final List <T> pattern, final List <T> matcher)
{
if (pattern.isEmpty())
return 0L;
T first = pattern.get (0);
int idx = matcher.indexOf (first);
long l = (pattern.size() - 1L) * idx;
pattern.remove (0);
matcher.remove (idx);
return l + invers (pattern, matcher);
}
/**
make a deep copy, since the called method will destroy the parameters
*/
public long invers (final List <T> lt)
{
List <T> copy = new ArrayList <T> (lilio.size());
copy.addAll (lilio);
return invers (lt, copy);
}
}
class PermutationIteratorTest {
public static List <Integer> genList (int... a) {
List <Integer> li = new ArrayList <Integer>();
for (int i: a)
li.add (i);
return li;
}
public static void main (String[] args) {
List <Integer> il = new ArrayList <Integer>();
// autoboxing, add '0' to 'z' as Character:
for (int c = 0; c < 3; ++c)
{
il.add (c);
}
PermutationIterable <Integer> pi = new PermutationIterable <Integer> (il);
for (List<Integer> li: pi)
show (li);
System.out.println ("-again-");
// do it a second time:
for (List <Integer> li: pi)
show (li);
// test the inverse:
System.out.println ("for (2,1,0) expecting 5 ?= " + pi.invers (genList (2, 1, 0)));
System.out.println ("for (2,0,1) expecting 4 ?= " + pi.invers (genList (2, 0, 1)));
System.out.println ("for (1,0,2) expecting 3 ?= " + pi.invers (genList (1, 2, 0)));
System.out.println ("for (1,2,0) expecting 2 ?= " + pi.invers (genList (1, 0, 2)));
System.out.println ("for (0,2,1) expecting 1 ?= " + pi.invers (genList (0, 2, 1)));
System.out.println ("for (0,1,2) expecting 0 ?= " + pi.invers (genList (0, 1, 2)));
Random r = new Random();
PermutationIterator <Integer> pitor = (PermutationIterator <Integer>) pi.iterator();
for (int i = 0; i < 10; ++i)
{
int rnd = r.nextInt ((int) pitor.last);
List <Integer> rli = pitor.get (rnd);
show (rli);
}
}
public static void show (List <?> lo) {
System.out.print ("(");
for (Object o: lo)
System.out.print (o);
System.out.println (")");
}
}
PermutationIterator chứa thêm, phương pháp công public List <T> get (final int code)
đó là tiện dụng, nếu bạn muốn chọn một hoán vị nhất định bởi chỉ số, ví dụ bằng cách ngẫu nhiên. Bạn biết kích thước (cuối cùng) và do đó có thể có một hoán vị của phạm vi hợp lệ theo chỉ mục.
PermutationTắt có chứa một phương pháp 'invers' sẽ tạo ra điều ngược lại: Chỉ số của một hoán vị nhất định.
Bên trong, invers và được việc đệ quy, nhưng tất cả các hoán vị không được sản xuất một cách đệ quy, vì vậy đây không phải là một vấn đề ngay cả đối với hoán vị lớn. Lưu ý rằng đối với 21 phần tử, bạn vượt quá kích thước của thời lượng và 20 bước đệ quy không phải là vấn đề.
Đệ quy là cách tự nhiên để giải quyết vấn đề này. Tại sao bạn muốn làm điều đó * mà không cần đệ quy *? Bất kỳ giải pháp "không đệ quy" hợp lý sẽ chỉ kết thúc bằng cách sử dụng một ngăn xếp riêng biệt để mô phỏng đệ quy anyway. –
@Greg Khả năng đọc có thể? Rất nhiều người tìm thấy đệ quy khó hiểu - có thể không sử dụng đệ quy sẽ làm cho ý định rõ ràng hơn? –
@drelihan: Một ví dụ về giải pháp không thể đọc được dễ hiểu hơn sẽ là cần thiết để hỗ trợ sự khẳng định đó. –