Originally Posted by
rcgldr
There's an iterative version of next_permutation that starts with a sorted array and ends up with a sorted array. It can be paused and continued at any time because the algorithm is driven off the out of order elements. I don't know if there's an optimized variation that can start with a sorted array and perform the equivalent of n cycles of permutations, given n (it could just perform n cycles).
I'm well aware. To be honest, I consider it a bit silly.
The reason I showed the swap sequence, above, is to show that theoretically, a single-swap -based approach might be available. If found, it would be significantly more efficient.
My permute() function above is what I'd use instead of the next_permutation(). Mine does just a single pass over the string for each permutation (although it does do a modulus and division for each element). For an N-character string, each call does N-1 swaps, divisions and modulos. Instead of relying on the order of the members in the array, it relies on the separate seed variable. To generate the next permutation, just increment the seed by one. All seed values from 0 to N!-1, inclusive, generate the N! unique permutations of an N-element array. Assuming unique array members; otherwise nonunique permutations are generated.
(Actually, all seed values generate only valid permutations. It's just that only the first N! ones are unique.)
Furthermore, I wrote
Originally Posted by
Nominal Animal
(If we were to consider the string as a number, plain swaps are not sufficient to generate the permutations in ascending or descending decimal value. It is possible with insertions, and there is an interesting pattern there that might make it easy to generate the next permutation, but generating the same permutations based on the seed looks too tricky to me.)
It turns out that the next_permutation() referred to ends up doing the above, except with repeated swaps to perform the insertion, and relying on the contents of the string itself to get it right. Here are the actual operations done, in order:
(s[0], s[1]) ← (s[1], s[1])
(s[0], s[1], s[2]) ← (s[1], s[2], s[0])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2]) ← (s[2], s[0], s[1])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2], s[3]) ← (s[2], s[1], s[3], s[0])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2]) ← (s[1], s[2], s[0])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2]) ← (s[2], s[0], s[1])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2], s[3]) ← (s[2], s[3], s[0], s[1])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2]) ← (s[1], s[2], s[0])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2]) ← (s[2], s[0], s[1])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2], s[3]) ← (s[3], s[1], s[0], s[2])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2]) ← (s[1], s[2], s[0])
(s[0], s[1]) ← (s[1], s[0])
(s[0], s[1], s[2]) ← (s[2], s[0], s[1])
(s[0], s[1]) ← (s[1], s[0])
where s[0] refers to least significant position, with increasing indexes indicating increasing significance (i.e. s[0] is the rightmost place).
If the string represents a decimal number with unique digits, initially digits in decreasing order from right (s[0]) to left (s[n]), say 1234, then each replacement step above creates the permutation with next larger value. The first five modifications apply to three-digit strings, and all twenty-three apply to four-digit strings.
(It is easy to generate more modifications, although I'm not exactly sure what the most efficient method to do so is. If nothing else, you can always use an order array, initialized to "digits", and perform the swaps on both the order array and the target string.)
Again, it's tricky to generate a specific permutation directly (e.g. nth from initial pattern), although I think I now have an approach that might work: the most significant digit of the string, in an N-digit string with seed 0≤seed<N!, is digit ⌊N seed / N!⌋ = ⌊seed/(N-1)!⌋ of the leftover digits (because they cover equal number of entries in the, uh, permutation space?), with 0 referring to the smallest digit left. To remove the digit from the seed, substract the value multiplied by (N-1)!. This should allow one to construct the permutation in reverse order.
(Consider an N-digit number that uses each digit only once. There are as many permutations that begin with digit N as they are those that begin with digit N-1, or any other digit, including 1. So, each possible highest digit "covers" equal number of permutations. Because there are N! permutations, there are exactly (N-1)! permutations that begin with digit N (or any particular digit). So, since the seed is 0≤seed<N!, we know that seeds 0≤seed<(N-1)! corresponds to permutations with the least significant digit available in the most significant position, and seeds (N-1)(N-1)!≤seed<N! correspond to permutation with the most significant digit available in the most significant position. Subtracting ⌊seed/(N-1)!⌋(N-1)! from seed "removes the most significant digit from the seed", so you can attack the next digit, if any are left, in the exact same way.)