Создание всех возможных перестановок списка рекурсивно

Я пытаюсь рекурсивно генерировать все элементы в списке рекурсивно. Я видел несколько решений подобных вопросов, но я не смог заставить свой код работать. Может кто-нибудь указать, как я могу исправить свой код?

это открыто для всех 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;
}