Создание всех возможных перестановок списка рекурсивно
Я пытаюсь рекурсивно генерировать все элементы в списке рекурсивно. Я видел несколько решений подобных вопросов, но я не смог заставить свой код работать. Может кто-нибудь указать, как я могу исправить свой код?
это открыто для всех S / O'ers, а не только для Java-людей.
(также я должен отметить, что он падает с таким исключением).
пример ввода: [1, 2, 3]
выход: [1, 2, 3] [1, 3, 2] [2, 1, 3] [2, 3, 1] [3, 1, 2] [3, 2, 1]
//allPossibleItems is an AL of all items
//this is called with generatePerm(null, new ArrayList<Item>);
private void generatePerm(Item i, ArrayList<Item> a) {
if(i != null) { a.add(i); }
if (a.size() == DESIRED_SIZE){
permutations.add(a);
return;
}
for(int j = 0; j < allPossibleItems.size(); j ++) {
if(allPossibleItems.get(j) != i)
generatePerm(allPossibleItems.get(j), a);
}
}
4 ответов
Если allPossibleItems содержит два разных элемента, x и y, то вы последовательно записываете x и y в список a, пока он не достигнет DESIRED_SIZE. Ты действительно этого хочешь? Если вы выберете DESIRED_SIZE достаточно большим, у вас будет слишком много рекурсивных вызовов в стеке, следовательно, исключение SO.
что я буду делать (если оригинал не имеет douplets / дубликаты):
public <E> List<List<E>> generatePerm(List<E> original) {
if (original.size() == 0) {
List<List<E>> result = new ArrayList<List<E>>();
result.add(new ArrayList<E>());
return result;
}
E firstElement = original.remove(0);
List<List<E>> returnValue = new ArrayList<List<E>>();
List<List<E>> permutations = generatePerm(original);
for (List<E> smallerPermutated : permutations) {
for (int index=0; index <= smallerPermutated.size(); index++) {
List<E> temp = new ArrayList<E>(smallerPermutated);
temp.add(index, firstElement);
returnValue.add(temp);
}
}
return returnValue;
}
проблема в том, что вам нужно клон ArrayList перед выполнением рекурсивного вызова. В противном случае вы будете добавлять всегда в один и тот же ArrayList.
//allPossibleItems is an AL of all items
//this is called with generatePerm(null, new ArrayList<Item>);
private void generatePerm(Item i, ArrayList<Item> a) {
if(i != null) { a.add(i); }
if (a.size() == DESIRED_SIZE){
permutations.add(a);
return;
}
for(int j = 0; j < allPossibleItems.size(); j ++) {
if(!a.contains(allPossibleItems.get(j))){
ArrayList<Item> b = clone(a);
generatePerm(allPossibleItems.get(j), b);
}
}
}
private List generatePerm(List a, int depth) {
// this is the method definition you want
// to generate all permutations, you need cycle thru all elements in your list and for each element
// add that element to each member of generatePerm(a, depth - 1);
// if you want combinations, you need to remove the element and then call
/// generateCombinations with the remaining list
}
Googling приведет меня к этому вопросу. я нашел метод ниже быстрее, чем другие методы.
в основном я использую набор для рекурсивного создания перестановок. Чтобы проиллюстрировать, первая позиция может содержать все возможные значения, вторая-все возможные значения, кроме первого, и так далее. Когда мы добрались до последней позиции, есть только одна возможность.
в терминах параметров рекурсивной функции (1) мы передаем то, что уже было записано как currentstring. (2) мы передаем Arraylist, который содержит результаты - list_of_permutes (3) мы передаем набор, из которого выбрать текущее число - currentnums. На последнем уровне у нас есть полная перестановка, которая затем добавляется в arraylist - list_of_permutes и возвращается вверх.
public static ArrayList recurse_nums(Set<Integer> currentnums, String currentstring, ArrayList list_of_permutes){
if(currentnums.size()==1){
int elem = currentnums.iterator().next();
list_of_permutes.add(currentstring + Integer.toString(elem));
return list_of_permutes;
}
for(int a:currentnums){
String newstring = currentstring + a;
Set<Integer> newnums = new HashSet<>();
newnums.addAll(currentnums);
newnums.remove(a);
recurse_nums(newnums, newstring,list_of_permutes);
}
return list_of_permutes;
}
Это можно вызвать из чего-то вроде следующего:
public static ArrayList permute_array(int[] arr){
Set<Integer> currentnums = new HashSet<>();
for (int i = 0; i < arr.length; i++) {currentnums.add(arr[i]);}
ArrayList permutations = new ArrayList();
recurse_nums(currentnums,"",permutations);
return permutations;
}