Algorithme pour générer toutes les permutations possibles d'une liste?

119

Disons que j'ai une liste de n éléments, je sais qu'il y en a n! moyens possibles de commander ces éléments. Qu'est-ce qu'un algorithme pour générer tous les ordres possibles de cette liste? Exemple, j'ai la liste [a, b, c]. L'algorithme renverrait [[a, b, c], [a, c, b,], [b, a, c], [b, c, a], [c, a, b], [c, b , une]].

Je lis ceci ici http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations

Mais Wikipédia n'a jamais été bon pour expliquer. Je n'y comprends pas grand-chose.

fent
la source
5
J'ai écrit une réponse détaillée à une autre question sur la génération de permutations une fois. Je pense que cela vous intéressera: stackoverflow.com/questions/1506078/…
Joren
2
Cela peut résoudre votre problème en.wikipedia.org/wiki/Heap's_algorithm
Felix

Réponses:

96

En gros, pour chaque élément de gauche à droite, toutes les permutations des éléments restants sont générées (et chacune est ajoutée avec les éléments courants). Cela peut être fait de manière récursive (ou itérative si vous aimez la douleur) jusqu'à ce que le dernier élément soit atteint, auquel point il n'y a qu'un seul ordre possible.

Donc avec la liste [1,2,3,4] toutes les permutations qui commencent par 1 sont générées, puis toutes les permutations qui commencent par 2, puis 3 puis 4.

Cela réduit efficacement le problème de la recherche de permutations d'une liste de quatre éléments à une liste de trois éléments. Après avoir réduit à 2 puis 1 listes d'éléments, toutes seront trouvées.
Exemple montrant des permutations de processus utilisant 3 boules colorées:
Image de permutations ordonnées de boules de couleur rouge, verte et bleue (à partir de https://en.wikipedia.org/wiki/Permutation#/media/File:Permutations_RGB.svg - https://commons.wikimedia.org/wiki/File:Permutations_RGB. svg )

Tourbillon
la source
2
J'ai pensé à cela au début aussi, mais ensuite l'élément actuel ne serait pas placé entre certains des éléments suivants. Toutes les permutations ne seraient donc pas générées.
fent le
@LLer désolé, a mis à jour ma réponse de "suivre" à "restant" pour clarifier. Cela fonctionne bien cependant. Vérifiez-le en écrivant le code et en vérifiant que vous obtenez 4! résultats différents.
WhirlWind
2
int permutations (int n, vecteur <int> a) {static int num_permutations = 0; if (n == (a.size () - 1)) {for (int i = 0; i <a.size (); i ++) cout << a [i] << ""; cout << "\ n"; num_permutations ++; } else {for (int i = n + 1; i <= a.size (); i ++) {permutations (n ​​+ 1, a); if (i <a.size ()) int temp = a [n], a [n] = a [i], a [i] = temp; }} return num_permutations; } int main (void) {vecteur <int> v; v.push_back (1); ... renvoyer les permutations (0, v); }
Dimanche
Oups - je ne sais pas comment formater le code dans un commentaire ... Testé le code avec 7 et obtenu 5040. Merci à @WhirlWind pour la suggestion.
Somesh
cet algo ne change-t-il pas si vous pouvez avoir 2 ou 3 boules rouges # 1, au lieu de seulement 1 de chaque couleur?
Alexander Mills
26

Voici un algorithme en Python qui fonctionne en place sur un tableau:

def permute(xs, low=0):
    if low + 1 >= len(xs):
        yield xs
    else:
        for p in permute(xs, low + 1):
            yield p        
        for i in range(low + 1, len(xs)):        
            xs[low], xs[i] = xs[i], xs[low]
            for p in permute(xs, low + 1):
                yield p        
            xs[low], xs[i] = xs[i], xs[low]

for p in permute([1, 2, 3, 4]):
    print p

Vous pouvez essayer le code par vous-même ici: http://repl.it/J9v

cdiggins
la source
Pouvez-vous expliquer la partie rendement? Je ne pouvais pas exécuter le code à sec. Merci d'avance.
Agniswar Bakshi
La question Stack Overflow sur stackoverflow.com/questions/104420/… indique qu'il existe un module de bibliothèque standard dans les versions 2.6 et suivantes et a une réponse fournissant une solution de 6 lignes dans une fonction pour obtenir des permutations de liste.
Edward le
@Agniswar En un coup d'œil, l'instruction yield est utilisée pour définir des générateurs, en remplaçant le retour d'une fonction pour fournir un résultat à son appelant sans détruire les variables locales. Contrairement à une fonction, où à chaque appel il commence avec un nouvel ensemble de variables, un générateur reprendra l'exécution là où elle a été interrompue. pythoncentral.io/python-generators-and-yield-keyword
MSS
Cette solution ne fonctionnera pas lors de la gestion d'une liste d'entrées identiques.
KaiserKatze
Merci d'avoir partagé. C'est intuitif et efficace, bien que la sortie ne soit pas dans l'ordre lexicographique.
Sam
16

Il y a déjà beaucoup de bonnes solutions ici, mais je voudrais partager comment j'ai résolu ce problème par moi-même et j'espère que cela pourrait être utile pour quelqu'un qui voudrait également trouver sa propre solution.

Après avoir réfléchi au problème, je suis arrivé à deux conclusions suivantes:

  1. Pour la liste Lde taille, nil y aura un nombre égal de solutions commençant par L 1 , L 2 ... L n éléments de la liste. Comme au total il y a des n!permutations de la liste de taille n, nous obtenons des n! / n = (n-1)!permutations dans chaque groupe.
  2. La liste de 2 éléments n'a que 2 permutations => [a,b]et [b,a].

En utilisant ces deux idées simples, j'ai dérivé l'algorithme suivant:

permute array
    if array is of size 2
       return first and second element as new array
       return second and first element as new array
    else
        for each element in array
            new subarray = array with excluded element
            return element + permute subarray

Voici comment j'ai implémenté cela en C #:

public IEnumerable<List<T>> Permutate<T>(List<T> input)
{
    if (input.Count == 2) // this are permutations of array of size 2
    {
        yield return new List<T>(input);
        yield return new List<T> {input[1], input[0]}; 
    }
    else
    {
        foreach(T elem in input) // going through array
        {
            var rlist = new List<T>(input); // creating subarray = array
            rlist.Remove(elem); // removing element
            foreach(List<T> retlist in Permutate(rlist))
            {
                retlist.Insert(0,elem); // inserting the element at pos 0
                yield return retlist;
            }

        }
    }
}
Alexandre Galkin
la source
16

La réponse de Wikipedia à «l'ordre lexicographique» me semble parfaitement explicite dans le style des livres de cuisine. Il cite une origine du 14ème siècle pour l'algorithme!

Je viens d'écrire une implémentation rapide en Java de l'algorithme de Wikipédia comme vérification et ce n'était pas un problème. Mais ce que vous avez dans votre Q comme exemple n'est PAS "lister toutes les permutations", mais "une LISTE de toutes les permutations", donc wikipedia ne vous sera pas d'une grande aide. Vous avez besoin d'un langage dans lequel les listes de permutations sont construites de manière réalisable. Et croyez-moi, les listes de quelques milliards de dollars ne sont généralement pas traitées dans des langages impératifs. Vous voulez vraiment un langage de programmation fonctionnel non strict, dans lequel les listes sont un objet de première classe, pour sortir des choses sans amener la machine près de la mort thermique de l'Univers.

C'est facile. En Haskell standard ou dans tout autre langage FP moderne:

-- perms of a list
perms :: [a] -> [ [a] ]
perms (a:as) = [bs ++ a:cs | perm <- perms as, (bs,cs) <- splits perm]
perms []     = [ [] ]

et

-- ways of splitting a list into two parts
splits :: [a] -> [ ([a],[a]) ]
splits []     = [ ([],[]) ]
splits (a:as) = ([],a:as) : [(a:bs,cs) | (bs,cs) <- splits as]
Peter Breuer
la source
9

Comme WhirlWind l'a dit, vous commencez par le début.

Vous échangez le curseur avec chaque valeur restante, y compris le curseur lui-même, ce sont toutes de nouvelles instances (j'ai utilisé un int[]et array.clone()dans l'exemple).

Ensuite, effectuez des permutations sur toutes ces différentes listes, en vous assurant que le curseur est à droite.

Lorsqu'il n'y a plus de valeurs restantes (le curseur est à la fin), imprimez la liste. C'est la condition d'arrêt.

public void permutate(int[] list, int pointer) {
    if (pointer == list.length) {
        //stop-condition: print or process number
        return;
    }
    for (int i = pointer; i < list.length; i++) {
        int[] permutation = (int[])list.clone();.
        permutation[pointer] = list[i];
        permutation[i] = list[pointer];
        permutate(permutation, pointer + 1);
    }
}
dinadineke
la source
8

Récursif demande toujours un effort mental à maintenir. Et pour les grands nombres, le factoriel est facilement énorme et le débordement de pile sera facilement un problème.

Pour les petits nombres (3 ou 4, ce qui est le plus souvent rencontré), les boucles multiples sont assez simples et directes. Il est regrettable que les réponses avec des boucles n'aient pas été votées.

Commençons par l'énumération (plutôt que la permutation). Lisez simplement le code sous forme de pseudo code Perl.

$foreach $i1 in @list
    $foreach $i2 in @list 
        $foreach $i3 in @list
            print "$i1, $i2, $i3\n"

L'énumération est plus souvent rencontrée que la permutation, mais si une permutation est nécessaire, ajoutez simplement les conditions:

$foreach $i1 in @list
    $foreach $i2 in @list 
        $if $i2==$i1
            next
        $foreach $i3 in @list
            $if $i3==$i1 or $i3==$i2
                next
            print "$i1, $i2, $i3\n"

Maintenant, si vous avez vraiment besoin d'une méthode générale potentiellement pour de grandes listes, nous pouvons utiliser la méthode radix. Tout d'abord, considérons le problème d'énumération:

$n=@list
my @radix
$for $i=0:$n
    $radix[$i]=0
$while 1
    my @temp
    $for $i=0:$n
        push @temp, $list[$radix[$i]]
    print join(", ", @temp), "\n"
    $call radix_increment

subcode: radix_increment
    $i=0
    $while 1
        $radix[$i]++
        $if $radix[$i]==$n
            $radix[$i]=0
            $i++
        $else
            last
    $if $i>=$n
        last

L'incrément de Radix est essentiellement le comptage des nombres (dans la base du nombre d'éléments de liste).

Maintenant, si vous avez besoin de permutation, ajoutez simplement les vérifications à l'intérieur de la boucle:

subcode: check_permutation
    my @check
    my $flag_dup=0
    $for $i=0:$n
        $check[$radix[$i]]++
        $if $check[$radix[$i]]>1
            $flag_dup=1
            last
    $if $flag_dup
        next

Edit: Le code ci-dessus devrait fonctionner, mais pour la permutation, radix_increment pourrait être un gaspillage. Donc, si le temps est une préoccupation pratique, nous devons changer radix_increment en permute_inc:

subcode: permute_init
    $for $i=0:$n
        $radix[$i]=$i

subcode: permute_inc                                       
    $max=-1                                                
    $for $i=$n:0                                           
        $if $max<$radix[$i]                                
            $max=$radix[$i]                                
        $else                                              
            $for $j=$n:0                                   
                $if $radix[$j]>$radix[$i]                  
                    $call swap, $radix[$i], $radix[$j]     
                    break                                  
            $j=$i+1                                        
            $k=$n-1                                        
            $while $j<$k                                   
                $call swap, $radix[$j], $radix[$k]         
                $j++                                       
                $k--                                       
            break                                          
    $if $i<0                                               
        break                                              

Bien sûr maintenant ce code est logiquement plus complexe, je vais partir à l'exercice du lecteur.

Hui Zhou
la source
7

entrez la description de l'image ici

// C program to print all permutations with duplicates allowed
#include <stdio.h>
#include <string.h>

/* Function to swap values at two pointers */
void swap(char *x, char *y)
{
    char temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

/* Function to print permutations of string
   This function takes three parameters:
   1. String
   2. Starting index of the string
   3. Ending index of the string. */

void permute(char *a, int l, int r)
{
   int i;
   if (l == r)
     printf("%s\n", a);
   else
   {
       for (i = l; i <= r; i++)
       {
          swap((a+l), (a+i));
          permute(a, l+1, r);
          swap((a+l), (a+i)); //backtrack
       }
   }
}

/* Driver program to test above functions */
int main()
{
    char str[] = "ABC";
    int n = strlen(str);
    permute(str, 0, n-1);
    return 0;
}

Référence: Geeksforgeeks.org

Sazzad Hissain Khan
la source
5

Si quelqu'un se demande comment faire en permutation en javascript.

Idée / pseudocode

  1. choisissez un élément à la fois
  2. permute le reste de l'élément, puis ajoute l'élément choisi à l'ensemble de la permutation

par exemple. 'a' + permute (bc). permute de bc serait bc & cb. Maintenant, ajoutez ces deux qui donneront abc, acb. de même, choisissez b + permute (ac) fournira bac, bca ... et continuez.

regarde maintenant le code

function permutations(arr){

   var len = arr.length, 
       perms = [],
       rest,
       picked,
       restPerms,
       next;

    //for one or less item there is only one permutation 
    if (len <= 1)
        return [arr];

    for (var i=0; i<len; i++)
    {
        //copy original array to avoid changing it while picking elements
        rest = Object.create(arr);

        //splice removed element change array original array(copied array)
        //[1,2,3,4].splice(2,1) will return [3] and remaining array = [1,2,4]
        picked = rest.splice(i, 1);

        //get the permutation of the rest of the elements
        restPerms = permutations(rest);

       // Now concat like a+permute(bc) for each
       for (var j=0; j<restPerms.length; j++)
       {
           next = picked.concat(restPerms[j]);
           perms.push(next);
       }
    }

   return perms;
}

Prenez votre temps pour comprendre cela. J'ai obtenu ce code de ( pertumation en JavaScript )

Jhankar Mahbub
la source
Je pensais à quelque chose de similaire, mais ne devriez-vous pas ajouter l'élément sélectionné à la fois à l'avant et à la fin des restParams? Dans ce cas, pour 'abc', si vous choisissez a, les permutations 'bc' sont 'bc' et 'cb'. Quand vous rajoutez 'a' à la liste, ne devriez-vous pas l'ajouter au début comme 'a + bc' + 'a + cb' mais aussi à la fin comme 'bc + a' + 'cb + a' de la liste?
Artimus
Vous obtiendrez ces permutations lorsque vous permuterez en commençant par «b» et «c» respectivement. (c'est-à-dire les deuxième et troisième passages de la boucle extérieure «for»)
Ryan O'Neill
3

Un autre en Python, il n'est pas en place comme celui de @ cdiggins, mais je pense que c'est plus facile à comprendre

def permute(num):
    if len(num) == 2:
        # get the permutations of the last 2 numbers by swapping them
        yield num
        num[0], num[1] = num[1], num[0]
        yield num
    else:
        for i in range(0, len(num)):
            # fix the first number and get the permutations of the rest of numbers
            for perm in permute(num[0:i] + num[i+1:len(num)]):
                yield [num[i]] + perm

for p in permute([1, 2, 3, 4]):
    print p
zhywu
la source
3

Je pensais écrire un code pour obtenir les permutations de tout entier donné de n'importe quelle taille, c'est-à-dire en fournissant un nombre 4567, nous obtenons toutes les permutations possibles jusqu'à 7654 ... J'ai donc travaillé dessus et trouvé un algorithme et finalement mis en œuvre, ici est le code écrit en "c". Vous pouvez simplement le copier et l'exécuter sur n'importe quel compilateur open source. Mais certaines failles attendent d'être déboguées. Veuillez apprécier.

Code:

#include <stdio.h>
#include <conio.h>
#include <malloc.h>

                //PROTOTYPES

int fact(int);                  //For finding the factorial
void swap(int*,int*);           //Swapping 2 given numbers
void sort(int*,int);            //Sorting the list from the specified path
int imax(int*,int,int);         //Finding the value of imax
int jsmall(int*,int);           //Gives position of element greater than ith but smaller than rest (ahead of imax)
void perm();                    //All the important tasks are done in this function


int n;                         //Global variable for input OR number of digits

void main()
{
int c=0;

printf("Enter the number : ");
scanf("%d",&c);
perm(c);
getch();
}

void perm(int c){
int *p;                     //Pointer for allocating separate memory to every single entered digit like arrays
int i, d;               
int sum=0;
int j, k;
long f;

n = 0;

while(c != 0)               //this one is for calculating the number of digits in the entered number
{
    sum = (sum * 10) + (c % 10);
    n++;                            //as i told at the start of loop
    c = c / 10;
}

f = fact(n);                        //It gives the factorial value of any number

p = (int*) malloc(n*sizeof(int));                //Dynamically allocation of array of n elements

for(i=0; sum != 0 ; i++)
{
    *(p+i) = sum % 10;                               //Giving values in dynamic array like 1234....n separately
    sum = sum / 10;
}

sort(p,-1);                                         //For sorting the dynamic array "p"

for(c=0 ; c<f/2 ; c++) {                        //Most important loop which prints 2 numbers per loop, so it goes upto 1/2 of fact(n)

    for(k=0 ; k<n ; k++)
        printf("%d",p[k]);                       //Loop for printing one of permutations
    printf("\n");

    i = d = 0;
    i = imax(p,i,d);                            //provides the max i as per algo (i am restricted to this only)
    j = i;
    j = jsmall(p,j);                            //provides smallest i val as per algo
    swap(&p[i],&p[j]);

    for(k=0 ; k<n ; k++)
        printf("%d",p[k]);
    printf("\n");

    i = d = 0;
    i = imax(p,i,d);
    j = i;
    j = jsmall(p,j);
    swap(&p[i],&p[j]);

    sort(p,i);
}
free(p);                                        //Deallocating memory
}

int fact (int a)
{
long f=1;
while(a!=0)
{
    f = f*a;
    a--;
}
return f;
}


void swap(int *p1,int *p2)
{
int temp;
temp = *p1;
*p1 = *p2;
*p2 = temp;
return;
}


void sort(int*p,int t)
{
int i,temp,j;
for(i=t+1 ; i<n-1 ; i++)
{
    for(j=i+1 ; j<n ; j++)
    {
        if(*(p+i) > *(p+j))
        {
            temp = *(p+i);
            *(p+i) = *(p+j);
            *(p+j) = temp;
        }
    }
}
}


int imax(int *p, int i , int d)
{
    while(i<n-1 && d<n-1)
{
    if(*(p+d) < *(p+d+1))
    {   
        i = d;
        d++;
    }
    else
        d++;
}
return i;
}


int jsmall(int *p, int j)
{
int i,small = 32767,k = j;
for (i=j+1 ; i<n ; i++)
{
    if (p[i]<small && p[i]>p[k])
    {     
       small = p[i];
       j = i;
    }
}
return j;
}
FreakPirate
la source
3
void permutate(char[] x, int i, int n){
    x=x.clone();
    if (i==n){
        System.out.print(x);
        System.out.print(" ");
        counter++;}
    else
    {
        for (int j=i; j<=n;j++){
     //   System.out.print(temp); System.out.print(" ");    //Debugger
        swap (x,i,j);
      //  System.out.print(temp); System.out.print(" "+"i="+i+" j="+j+"\n");// Debugger
        permutate(x,i+1,n);
    //    swap (temp,i,j);
    }
    }
}

void swap (char[] x, int a, int b){
char temp = x[a];
x[a]=x[b];
x[b]=temp;
}

J'ai créé celui-ci. basé sur des recherches trop permutées (qwe, 0, qwe.length-1); Juste pour que vous le sachiez, vous pouvez le faire avec ou sans retour en arrière

Luigi Mackenzie C. Brito
la source
3

Voici une méthode de jouet Ruby qui fonctionne comme #permutation.to_aça pourrait être plus lisible pour les fous. C'est hella lent, mais aussi 5 lignes.

def permute(ary)
  return [ary] if ary.size <= 1
  ary.collect_concat.with_index do |e, i|
    rest = ary.dup.tap {|a| a.delete_at(i) }
    permute(rest).collect {|a| a.unshift(e) }
  end
end
Jenner La Fave
la source
3

J'ai écrit cette solution récursive en ANSI C. Chaque exécution de la fonction Permutate fournit une permutation différente jusqu'à ce que tout soit terminé. Les variables globales peuvent également être utilisées pour les variables fact et count.

#include <stdio.h>
#define SIZE 4

void Rotate(int vec[], int size)
{
    int i, j, first;

    first = vec[0];
    for(j = 0, i = 1; i < size; i++, j++)
    {
        vec[j] = vec[i];
    }
    vec[j] = first;
}

int Permutate(int *start, int size, int *count)
{
    static int fact;

    if(size > 1)
    {
        if(Permutate(start + 1, size - 1, count))
        {
            Rotate(start, size);
        }
        fact *= size;
    }
    else
    {
        (*count)++;
        fact = 1;
    }

    return !(*count % fact);
}

void Show(int vec[], int size)
{
    int i;

    printf("%d", vec[0]);
    for(i = 1; i < size; i++)
    {
        printf(" %d", vec[i]);
    }
    putchar('\n');
}

int main()
{
    int vec[] = { 1, 2, 3, 4, 5, 6 }; /* Only the first SIZE items will be permutated */
    int count = 0;

    do
    {
        Show(vec, SIZE);
    } while(!Permutate(vec, SIZE, &count));

    putchar('\n');
    Show(vec, SIZE);
    printf("\nCount: %d\n\n", count);

    return 0;
}
Horacio
la source
3

Version Java

/**
 * @param uniqueList
 * @param permutationSize
 * @param permutation
 * @param only            Only show the permutation of permutationSize,
 *                        else show all permutation of less than or equal to permutationSize.
 */
public static void my_permutationOf(List<Integer> uniqueList, int permutationSize, List<Integer> permutation, boolean only) {
    if (permutation == null) {
        assert 0 < permutationSize && permutationSize <= uniqueList.size();
        permutation = new ArrayList<>(permutationSize);
        if (!only) {
            System.out.println(Arrays.toString(permutation.toArray()));
        }
    }
    for (int i : uniqueList) {
        if (permutation.contains(i)) {
            continue;
        }
        permutation.add(i);
        if (!only) {
            System.out.println(Arrays.toString(permutation.toArray()));
        } else if (permutation.size() == permutationSize) {
            System.out.println(Arrays.toString(permutation.toArray()));
        }
        if (permutation.size() < permutationSize) {
            my_permutationOf(uniqueList, permutationSize, permutation, only);
        }
        permutation.remove(permutation.size() - 1);
    }
}

Par exemple

public static void main(String[] args) throws Exception { 
    my_permutationOf(new ArrayList<Integer>() {
        {
            add(1);
            add(2);
            add(3);

        }
    }, 3, null, true);
}

production:

  [1, 2, 3]
  [1, 3, 2]
  [2, 1, 3]
  [2, 3, 1]
  [3, 1, 2]
  [3, 2, 1]
Bruce Zu
la source
3

en PHP

$set=array('A','B','C','D');

function permutate($set) {
    $b=array();
    foreach($set as $key=>$value) {
        if(count($set)==1) {
            $b[]=$set[$key];
        }
        else {
            $subset=$set;
            unset($subset[$key]);
            $x=permutate($subset);
            foreach($x as $key1=>$value1) {
                $b[]=$value.' '.$value1;
            }
        }
    }
    return $b;
}

$x=permutate($set);
var_export($x);
nerdface
la source
3

Voici le code en Python pour imprimer toutes les permutations possibles d'une liste:

def next_perm(arr):
    # Find non-increasing suffix
    i = len(arr) - 1
    while i > 0 and arr[i - 1] >= arr[i]:
        i -= 1
    if i <= 0:
        return False

    # Find successor to pivot
    j = len(arr) - 1
    while arr[j] <= arr[i - 1]:
        j -= 1
    arr[i - 1], arr[j] = arr[j], arr[i - 1]

    # Reverse suffix
    arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
    print arr
    return True

def all_perm(arr):
    a = next_perm(arr)
    while a:
        a = next_perm(arr)
    arr = raw_input()
    arr.split(' ')
    arr = map(int, arr)
    arr.sort()
    print arr
    all_perm(arr)

J'ai utilisé un algorithme d'ordre lexicographique pour obtenir toutes les permutations possibles, mais un algorithme récursif est plus efficace. Vous pouvez trouver le code de l'algorithme récursif ici: Permutations de récursivité Python

Anuj Mittal
la source
3
public class PermutationGenerator
{
    private LinkedList<List<int>> _permutationsList;
    public void FindPermutations(List<int> list, int permutationLength)
    {
        _permutationsList = new LinkedList<List<int>>();
        foreach(var value in list)
        {
            CreatePermutations(value, permutationLength);
        }
    }

    private void CreatePermutations(int value, int permutationLength)
    {
        var node = _permutationsList.First;
        var last = _permutationsList.Last;
        while (node != null)
        {
            if (node.Value.Count < permutationLength)
            {
                GeneratePermutations(node.Value, value, permutationLength);
            }
            if (node == last)
            {
                break;
            }
            node = node.Next;
        }

        List<int> permutation = new List<int>();
        permutation.Add(value);
        _permutationsList.AddLast(permutation);
    }

    private void GeneratePermutations(List<int> permutation, int value, int permutationLength)
    {
       if (permutation.Count < permutationLength)
        {
            List<int> copyOfInitialPermutation = new List<int>(permutation);
            copyOfInitialPermutation.Add(value);
            _permutationsList.AddLast(copyOfInitialPermutation);
            List<int> copyOfPermutation = new List<int>();
            copyOfPermutation.AddRange(copyOfInitialPermutation);
            int lastIndex = copyOfInitialPermutation.Count - 1;
            for (int i = lastIndex;i > 0;i--)
            {
                int temp = copyOfPermutation[i - 1];
                copyOfPermutation[i - 1] = copyOfPermutation[i];
                copyOfPermutation[i] = temp;

                List<int> perm = new List<int>();
                perm.AddRange(copyOfPermutation);
                _permutationsList.AddLast(perm);
            }
        }
    }

    public void PrintPermutations(int permutationLength)
    {
        int count = _permutationsList.Where(perm => perm.Count() == permutationLength).Count();
        Console.WriteLine("The number of permutations is " + count);
    }
}
Bahruz Balabayov
la source
c'est une réponse utile
Ayaz Alifov
2

Dans Scala

    def permutazione(n: List[Int]): List[List[Int]] = permutationeAcc(n, Nil)



def permutationeAcc(n: List[Int], acc: List[Int]): List[List[Int]] = {

    var result: List[List[Int]] = Nil
    for (i ← n if (!(acc contains (i))))
        if (acc.size == n.size-1)
            result = (i :: acc) :: result
        else
            result = result ::: permutationeAcc(n, i :: acc)
    result
}
Marco
la source
2

ceci est une version java pour la permutation

public class Permutation {

    static void permute(String str) {
        permute(str.toCharArray(), 0, str.length());
    }

    static void permute(char [] str, int low, int high) {
        if (low == high) {
            System.out.println(str);
            return;
        }

        for (int i=low; i<high; i++) {
            swap(str, i, low);
            permute(str, low+1, high);
            swap(str, low, i);
        }

    }

    static void swap(char [] array, int i, int j) {
        char t = array[i];
        array[i] = array[j];
        array[j] = t;
    }
}
杨小勇
la source
2

Voici une implémentation pour ColdFusion (nécessite CF10 en raison de l'argument de fusion de ArrayAppend ()):

public array function permutateArray(arr){

    if (not isArray(arguments.arr) ) {
        return ['The ARR argument passed to the permutateArray function is not of type array.'];    
    }

    var len = arrayLen(arguments.arr);
    var perms = [];
    var rest = [];
    var restPerms = [];
    var rpLen = 0;
    var next = [];

    //for one or less item there is only one permutation 
    if (len <= 1) {
        return arguments.arr;
    }

    for (var i=1; i <= len; i++) {
        // copy the original array so as not to change it and then remove the picked (current) element
        rest = arraySlice(arguments.arr, 1);
        arrayDeleteAt(rest, i);

         // recursively get the permutation of the rest of the elements
         restPerms = permutateArray(rest);
         rpLen = arrayLen(restPerms);

        // Now concat each permutation to the current (picked) array, and append the concatenated array to the end result
        for (var j=1; j <= rpLen; j++) {
            // for each array returned, we need to make a fresh copy of the picked(current) element array so as to not change the original array
            next = arraySlice(arguments.arr, i, 1);
            arrayAppend(next, restPerms[j], true);
            arrayAppend(perms, next);
        }
     }

    return perms;
}

Basé sur la solution js de KhanSharp ci-dessus.

oreillefl
la source
Une explication de la stratégie globale de votre algorithme serait un bon moyen d'améliorer cette réponse.
Richard
Alors, pourquoi le vote négatif? Ceci est une mise en œuvre fonctionnelle.
earachefl
@Richard, la stratégie globale a été expliquée ci-dessus par Whirlwind et d'autres. Je ne vois pas votre commentaire sur toutes les autres réponses affichées comme implémentations sans explications.
earachefl
1

Je sais que c'est un très très ancien et même hors sujet dans le stackoverflow d'aujourd'hui, mais je voulais toujours apporter une réponse javascript amicale pour la simple raison qu'elle s'exécute dans votre navigateur.

J'ai également ajouté le debuggerpoint d'arrêt de la directive afin que vous puissiez parcourir le code (chrome requis) pour voir comment cet algorithme fonctionne. Ouvrez votre console de développement dans Chrome ( F12sous Windows ouCMD + OPTION + I sur Mac), puis cliquez sur "Exécuter l'extrait de code". Cela implémente le même algorithme exact que @WhirlWind a présenté dans sa réponse.

Votre navigateur doit interrompre l'exécution au niveau de la debuggerdirective. UtilisationF8 pour continuer l'exécution du code.

Parcourez le code et voyez comment cela fonctionne!

function permute(rest, prefix = []) {
  if (rest.length === 0) {
    return [prefix];
  }
  return (rest
    .map((x, index) => {
      const oldRest = rest;
      const oldPrefix = prefix;
      // the `...` destructures the array into single values flattening it
      const newRest = [...rest.slice(0, index), ...rest.slice(index + 1)];
      const newPrefix = [...prefix, x];
      debugger;

      const result = permute(newRest, newPrefix);
      return result;
    })
    // this step flattens the array of arrays returned by calling permute
    .reduce((flattened, arr) => [...flattened, ...arr], [])
  );
}
console.log(permute([1, 2, 3]));

Rico Kahler
la source
1

Dans la solution Java suivante, nous tirons parti du fait que les chaînes sont immuables afin d'éviter de cloner le jeu de résultats à chaque itération.

L'entrée sera une chaîne, disons "abc", et la sortie sera toutes les permutations possibles:

abc
acb
bac
bca
cba
cab

Code:

public static void permute(String s) {
    permute(s, 0);
}

private static void permute(String str, int left){
    if(left == str.length()-1) {
        System.out.println(str);
    } else {
        for(int i = left; i < str.length(); i++) {
            String s = swap(str, left, i);
            permute(s, left+1);
        }
    }
}

private static String swap(String s, int left, int right) {
    if (left == right)
        return s;

    String result = s.substring(0, left);
    result += s.substring(right, right+1);
    result += s.substring(left+1, right);
    result += s.substring(left, left+1);
    result += s.substring(right+1);
    return result;
}

La même approche peut être appliquée aux tableaux (au lieu d'une chaîne):

public static void main(String[] args) {
    int[] abc = {1,2,3};
    permute(abc, 0);
}
public static void permute(int[] arr, int index) {
    if (index == arr.length) {
        System.out.println(Arrays.toString(arr));
    } else {
        for (int i = index; i < arr.length; i++) {
            int[] permutation = arr.clone();
            permutation[index] = arr[i];
            permutation[i] = arr[index];
            permute(permutation, index + 1);
        }
    }
}
Nir Alfasi
la source
1

C'est ma solution sur Java:

public class CombinatorialUtils {

    public static void main(String[] args) {
        List<String> alphabet = new ArrayList<>();
        alphabet.add("1");
        alphabet.add("2");
        alphabet.add("3");
        alphabet.add("4");

        for (List<String> strings : permutations(alphabet)) {
            System.out.println(strings);
        }
        System.out.println("-----------");
        for (List<String> strings : combinations(alphabet)) {
            System.out.println(strings);
        }
    }

    public static List<List<String>> combinations(List<String> alphabet) {
        List<List<String>> permutations = permutations(alphabet);
        List<List<String>> combinations = new ArrayList<>(permutations);

        for (int i = alphabet.size(); i > 0; i--) {
            final int n = i;
            combinations.addAll(permutations.stream().map(strings -> strings.subList(0, n)).distinct().collect(Collectors.toList()));
        }
        return combinations;
    }

    public static <T> List<List<T>> permutations(List<T> alphabet) {
        ArrayList<List<T>> permutations = new ArrayList<>();
        if (alphabet.size() == 1) {
            permutations.add(alphabet);
            return permutations;
        } else {
            List<List<T>> subPerm = permutations(alphabet.subList(1, alphabet.size()));
            T addedElem = alphabet.get(0);
            for (int i = 0; i < alphabet.size(); i++) {
                for (List<T> permutation : subPerm) {
                    int index = i;
                    permutations.add(new ArrayList<T>(permutation) {{
                        add(index, addedElem);
                    }});
                }
            }
        }
        return permutations;
    }
}
user2153604
la source
1

Vous ne pouvez pas vraiment parler de résolution d'un problème de permultation en récursivité sans publier une implémentation dans un (dialecte de) langage qui a lancé l'idée . Donc, par souci d'exhaustivité, voici l'une des méthodes qui peuvent être faites dans Scheme.

(define (permof wd)
  (cond ((null? wd) '())
        ((null? (cdr wd)) (list wd))
        (else
         (let splice ([l '()] [m (car wd)] [r (cdr wd)])
           (append
            (map (lambda (x) (cons m x)) (permof (append l r)))
            (if (null? r)
                '()
                (splice (cons m l) (car r) (cdr r))))))))

en appelant (permof (list "foo" "bar" "baz"))nous aurons:

'(("foo" "bar" "baz")
  ("foo" "baz" "bar")
  ("bar" "foo" "baz")
  ("bar" "baz" "foo")
  ("baz" "bar" "foo")
  ("baz" "foo" "bar"))

Je n'entrerai pas dans les détails de l'algorithme car cela a été suffisamment expliqué dans d'autres articles. L'idée est la même.

Cependant, les problèmes récursifs ont tendance à être beaucoup plus difficiles à modéliser et à réfléchir dans un milieu destructeur comme Python, C et Java, alors qu'en Lisp ou ML, ils peuvent être exprimés de manière concise.

Tarte 'Oh' Pah
la source
0

Voici une solution récursive en PHP. Le message de WhirlWind décrit avec précision la logique. Il convient de mentionner que la génération de toutes les permutations s'exécute en temps factoriel, il peut donc être judicieux d'utiliser une approche itérative à la place.

public function permute($sofar, $input){
  for($i=0; $i < strlen($input); $i++){
    $diff = strDiff($input,$input[$i]);
    $next = $sofar.$input[$i]; //next contains a permutation, save it
    $this->permute($next, $diff);
  }
}

La fonction strDiff prend deux chaînes, s1et s2, et retourne une nouvelle chaîne avec tout ce qui est s1sans éléments dans s2(les doublons comptent). Donc, strDiff('finish','i')=> 'fnish'(le deuxième «i» n'est pas supprimé).

Anthony Naddeo
la source
0

Voici un algorithme en R, au cas où quelqu'un aurait besoin d'éviter de charger des bibliothèques supplémentaires comme je devais le faire.

permutations <- function(n){
    if(n==1){
        return(matrix(1))
    } else {
        sp <- permutations(n-1)
        p <- nrow(sp)
        A <- matrix(nrow=n*p,ncol=n)
        for(i in 1:n){
            A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))
        }
        return(A)
    }
}

Exemple d'utilisation:

> matrix(letters[permutations(3)],ncol=3)
     [,1] [,2] [,3]
[1,] "a"  "b"  "c" 
[2,] "a"  "c"  "b" 
[3,] "b"  "a"  "c" 
[4,] "b"  "c"  "a" 
[5,] "c"  "a"  "b" 
[6,] "c"  "b"  "a" 
Musclé
la source
0
#!/usr/bin/env python
import time

def permutations(sequence):
  # print sequence
  unit = [1, 2, 1, 2, 1]

  if len(sequence) >= 4:
    for i in range(4, (len(sequence) + 1)):
      unit = ((unit + [i - 1]) * i)[:-1]
      # print unit
    for j in unit:
      temp = sequence[j]
      sequence[j] = sequence[0]
      sequence[0] = temp
      yield sequence
  else:
    print 'You can use PEN and PAPER'


# s = [1,2,3,4,5,6,7,8,9,10]
s = [x for x in 'PYTHON']

print s

z = permutations(s)
try:
  while True:
    # time.sleep(0.0001)
    print next(z)
except StopIteration:
    print 'Done'

['P', 'Y', 'T', 'H', 'O', 'N']
['Y', 'P', 'T', 'H', 'O', 'N']
['T', 'P', 'Y', 'H', 'O', 'N']
['P', 'T', 'Y', 'H', 'O', 'N']
['Y', 'T', 'P', 'H', 'O', 'N']
['T', 'Y', 'P', 'H', 'O', 'N']
['H', 'Y', 'P', 'T', 'O', 'N']
['Y', 'H', 'P', 'T', 'O', 'N']
['P', 'H', 'Y', 'T', 'O', 'N']
['H', 'P', 'Y', 'T', 'O', 'N']
['Y', 'P', 'H', 'T', 'O', 'N']
['P', 'Y', 'H', 'T', 'O', 'N']
['T', 'Y', 'H', 'P', 'O', 'N']
['Y', 'T', 'H', 'P', 'O', 'N']
['H', 'T', 'Y', 'P', 'O', 'N']
['T', 'H', 'Y', 'P', 'O', 'N']
['Y', 'H', 'T', 'P', 'O', 'N']
['H', 'Y', 'T', 'P', 'O', 'N']
['P', 'Y', 'T', 'H', 'O', 'N']
.
.
.
['Y', 'T', 'N', 'H', 'O', 'P']
['N', 'T', 'Y', 'H', 'O', 'P']
['T', 'N', 'Y', 'H', 'O', 'P']
['Y', 'N', 'T', 'H', 'O', 'P']
['N', 'Y', 'T', 'H', 'O', 'P']
mahmoh
la source
La solution montre que vous n'avez pas permuté la chaîne selon l'exigence. La deuxième permutation aurait dû être PYTHNO
Rahul Kadukar
0

Il s'agit d'un code récursif pour java, l'idée est d'avoir un préfixe qui ajoute le reste des caractères:

public static void permutation(String str) { 
    permutation("", str); 
}

private static void permutation(String prefix, String str) {
    int n = str.length();
    if (n == 0) System.out.println(prefix);
    else {
        for (int i = 0; i < n; i++)
            permutation(prefix + str.charAt(i), str);
    }
}

Exemple:

Entrée = "ABC"; Production:

ABC ACB BAC BCA CAB CBA

Rafael Amsili
la source
1
Bonne idée, mais je pense que vous devriez également supprimer charAt (i) strlors d'un appel récursif, sinon il ne se terminera pas.
Crystal
1
Si vous voulez copier et coller, vous devez (1) donner une attribution et (2) vous assurer que toutes les modifications sont correctes. Pour l'attribution, il s'agit de perm1 de introcs.cs.princeton.edu/java/23recursion/… . De plus, votre modification est incorrecte: str.substring (0, i) + str.substring (i + 1, n) n'est pas identique à str, car le premier omet le caractère à la position i.
kevin
0

Juste pour être complet, C ++

#include <iostream>
#include <algorithm>
#include <string>

std::string theSeq = "abc";
do
{
  std::cout << theSeq << endl;
} 
while (std::next_permutation(theSeq.begin(), theSeq.end()));

...

abc
acb
bac
bca
cab
cba
AndersK
la source
0

Voici une solution non récursive en C ++ qui fournit la permutation suivante dans l'ordre croissant, de la même manière que la fonctionnalité fournie par std :: next_permutation:

void permute_next(vector<int>& v)
{
  if (v.size() < 2)
    return;

  if (v.size() == 2)
  { 
    int tmp = v[0];
    v[0] = v[1];
    v[1] = tmp;
    return;
  }

  // Step 1: find first ascending-ordered pair from right to left
  int i = v.size()-2;
  while(i>=0)
  { 
    if (v[i] < v[i+1])
      break;
    i--;
  }
  if (i<0) // vector fully sorted in descending order (last permutation)
  {
    //resort in ascending order and return
    sort(v.begin(), v.end());
    return;
  }

  // Step 2: swap v[i] with next higher element of remaining elements
  int pos = i+1;
  int val = v[pos];
  for(int k=i+2; k<v.size(); k++)
    if(v[k] < val && v[k] > v[i])
    {
      pos = k;
      val = v[k];
    }
  v[pos] = v[i];
  v[i] = val;

  // Step 3: sort remaining elements from i+1 ... end
  sort(v.begin()+i+1, v.end());
}
Marios Choudary
la source