En supposant que nous parlons d'ordre lexicographique sur les valeurs permutées, il existe deux approches générales que vous pouvez utiliser:
- transformer une permutation des éléments en permutation suivante (comme ShreevatsaR l'a posté), ou
- calculez directement la
n
ième permutation, en comptant n
de 0 vers le haut.
Pour ceux (comme moi ;-) qui ne parlent pas c ++ en tant que natifs, l'approche 1 peut être implémentée à partir du pseudo-code suivant, en supposant l'indexation de base zéro d'un tableau d'index zéro sur la "gauche" (en remplaçant une autre structure , comme une liste, est "laissée comme exercice" ;-):
1. scan the array from right-to-left (indices descending from N-1 to 0)
1.1. if the current element is less than its right-hand neighbor,
call the current element the pivot,
and stop scanning
1.2. if the left end is reached without finding a pivot,
reverse the array and return
(the permutation was the lexicographically last, so its time to start over)
2. scan the array from right-to-left again,
to find the rightmost element larger than the pivot
(call that one the successor)
3. swap the pivot and the successor
4. reverse the portion of the array to the right of where the pivot was found
5. return
Voici un exemple commençant par une permutation actuelle de CADB:
1. scanning from the right finds A as the pivot in position 1
2. scanning again finds B as the successor in position 3
3. swapping pivot and successor gives CBDA
4. reversing everything following position 1 (i.e. positions 2..3) gives CBAD
5. CBAD is the next permutation after CADB
Pour la seconde approche (calcul direct de la n
ème permutation), rappelons qu'il existe des N!
permutations d' N
éléments. Par conséquent, si vous permutez des N
éléments, les premières (N-1)!
permutations doivent commencer par le plus petit élément, les (N-1)!
permutations suivantes doivent commencer par le deuxième plus petit, et ainsi de suite. Cela conduit à l'approche récursive suivante (toujours en pseudo-code, en numérotant les permutations et les positions à partir de 0):
To find permutation x of array A, where A has N elements:
0. if A has one element, return it
1. set p to ( x / (N-1)! ) mod N
2. the desired permutation will be A[p] followed by
permutation ( x mod (N-1)! )
of the elements remaining in A after position p is removed
Ainsi, par exemple, la 13e permutation d'ABCD se trouve comme suit:
perm 13 of ABCD: {p = (13 / 3!) mod 4 = (13 / 6) mod 4 = 2
C followed by perm 1 of ABD {because 13 mod 3! = 13 mod 6 = 1}
perm 1 of ABD: {p = (1 / 2!) mod 3 = (1 / 2) mod 2 = 0
A followed by perm 1 of BD {because 1 mod 2! = 1 mod 2 = 1}
perm 1 of BD: {p = (1 / 1!) mod 2 = (1 / 1) mod 2 = 1
D followed by perm 0 of B {because 1 mod 1! = 1 mod 1 = 0}
B (because there's only one element)
DB
ADB
CADB
Incidemment, la "suppression" d'éléments peut être représentée par un tableau parallèle de booléens qui indique quels éléments sont encore disponibles, il n'est donc pas nécessaire de créer un nouveau tableau à chaque appel récursif.
Donc, pour parcourir les permutations d'ABCD, comptez simplement de 0 à 23 (4! -1) et calculez directement la permutation correspondante.