Supponendo che stiamo parlando dell'ordine lessicografico sui valori permutati, ci sono due approcci generali che puoi usare:
- trasformare una permutazione degli elementi nella successiva permutazione (come postato da ShreevatsaR), o
- calcola direttamente la
n
th permutazione, contando n
da 0 in su.
Per quelli (come me ;-) che non parlano c ++ come nativi, l'approccio 1 può essere implementato dal seguente pseudo-codice, assumendo l'indicizzazione a base zero di un array con indice zero a "sinistra" (sostituendo qualche altra struttura , come una lista, è "lasciato come esercizio" ;-):
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
Ecco un esempio che inizia con una permutazione corrente di 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
Per il secondo approccio (calcolo diretto della n
th permutazione), ricorda che ci sono N!
permutazioni di N
elementi. Pertanto, se stai permutando N
elementi, le prime (N-1)!
permutazioni devono iniziare con l'elemento più piccolo, le successive (N-1)!
permutazioni devono iniziare con il secondo più piccolo e così via. Questo porta al seguente approccio ricorsivo (sempre in pseudo-codice, numerando le permutazioni e le posizioni da 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
Quindi, ad esempio, la 13a permutazione di ABCD si trova come segue:
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
Per inciso, la "rimozione" di elementi può essere rappresentata da un array parallelo di booleani che indica quali elementi sono ancora disponibili, quindi non è necessario creare un nuovo array ad ogni chiamata ricorsiva.
Quindi, per iterare attraverso le permutazioni di ABCD, conta da 0 a 23 (4! -1) e calcola direttamente la permutazione corrispondente.