Angenommen, es handelt sich um eine lexikografische Reihenfolge über die permutierten Werte, gibt es zwei allgemeine Ansätze, die Sie verwenden können:
- transformiere eine Permutation der Elemente in die nächste Permutation (wie von ShreevatsaR gepostet) oder
- Berechnen Sie direkt die
n
th-Permutation, während Sie n
von 0 aufwärts zählen.
Für diejenigen (wie ich ;-), die kein C ++ als Muttersprachler sprechen, kann Ansatz 1 aus dem folgenden Pseudocode implementiert werden, wobei eine auf Null basierende Indizierung eines Arrays mit dem Index Null auf der "linken Seite" angenommen wird (wobei eine andere Struktur ersetzt wird) , wie eine Liste, wird "als Übung belassen" ;-):
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
Hier ist ein Beispiel, das mit einer aktuellen Permutation von CADB beginnt:
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
Denken Sie beim zweiten Ansatz (direkte Berechnung der dritten n
Permutation) daran, dass es N!
Permutationen von N
Elementen gibt. Wenn Sie also N
Elemente permutieren , müssen die ersten (N-1)!
Permutationen mit dem kleinsten Element beginnen, die nächsten (N-1)!
Permutationen müssen mit dem zweitkleinsten beginnen und so weiter. Dies führt zu folgendem rekursiven Ansatz (wiederum im Pseudocode, Nummerierung der Permutationen und Positionen von 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
So wird zum Beispiel die 13. Permutation von ABCD wie folgt gefunden:
perm 13 of ABCD: {p = (13 / 3!) mod 4 = (13 / 6) mod 4 = 2; ABCD[2] = C}
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; ABD[0] = A}
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; BD[1] = D}
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
Im Übrigen kann das "Entfernen" von Elementen durch ein paralleles Array von Booleschen Werten dargestellt werden, das angibt, welche Elemente noch verfügbar sind, sodass nicht bei jedem rekursiven Aufruf ein neues Array erstellt werden muss.
Um die Permutationen von ABCD zu durchlaufen, zählen Sie einfach von 0 bis 23 (4! -1) und berechnen Sie die entsprechende Permutation direkt.