A Numeric Algorithm for Generating
Permutations in Lexicographic Order
with a C Implementation
©Afshin Tiraie
November 20, 2012
While we use a positional numeral system, base-Π, given n arrangeable objects, we are
required to produce all permutations of the objects in lexicographic order.
Let 0, 1, · · · , m denote all numbers less than the number of the objects increasingly.
Our goal is to derive a completely numeric algorithm (with no interchanges) for generating
all permutations of 0, 1, · · · , m as numerals in order. Due to the logical correspondence
between 0, 1, · · · , m and the objects, these permutations can be deemed those of the objects
in lexicographic order.
Decimal
Index i pi Representation of
pi − pi−1
0 0 1 2
1 0 2 1 2
2 1 0 2 4
3 1 2 0 4
4 2 0 1 4
5 2 1 0 2
Table 1: Base-ten-3 Permutations
Let Π be ten. Then if n = 2, using base-two system, writing 1 as the first permutation
of the digits of this system, 01, we can obtain the second permutation, 10, by adding 1 to
01. If n = 3, in base-three: 012 + 1 = 020, and 020 + 1 = 021. It is thus clear that using
base-n system when n ≤ Π, we can easily achieve our goal. It is also clear, however, that
when n > Π, base-n system cannot be considered. To overcome this difficulty, we define a
numeral system founded on base-Π and n where:
I. Each of base-Π numerals 0, 1, · · · , m, n, preserving its value is deemed a digit.
II. A number is denoted by a sequence of digits with | between each pair of adjacent digits.
1
III. |ar|ar−1| . . . |a0 represents the same number as ar × nr
+ ar−1 × nr−1
+ · · · + a0 × n0
in
base-Π.
We call this system base-Π-n. Thus, 10|1|0|11 in base-two-100 represents the same number
as the decimal 147(= 2×43
+42
+3). We omit bars when n ≤ Π; hence base-Π-10 and base-Π
can be considered identical. We use p0, p1, · · · pn!−1 to represent permutations of 0, 1, · · · , m
as numerals of base-Π-n in order.
Decimal
Index i pi Representation of
pi − pi−1
0 0 1 2 3
1 0 1 3 2 3
2 0 2 1 3 9
3 0 2 3 1 6
4 0 3 1 2 9
5 0 3 2 1 3
6 1 0 2 3 18
7 1 0 3 2 3
8 1 2 0 3 21
9 1 2 3 0 9
10 1 3 0 2 6
11 1 3 2 0 6
12 2 0 1 3 15
13 2 0 3 1 6
14 2 1 0 3 6
15 2 1 3 0 9
16 2 3 0 1 21
17 2 3 1 0 3
18 3 0 1 2 18
19 3 0 2 1 3
20 3 1 0 2 9
21 3 1 2 0 6
22 3 2 0 1 9
23 3 2 1 0 3
Table 2: Base-ten-4 Permutations
No matter how large n is, we can now calculate the permutations of base-Π-n. Tables 1
and 2 reveal:
Proposition. The difference of any two permutations in base-Π-n is a multiple of n − 1.
Since permutations are obtainable from one another through a sequence of transpositions,
this proposition is an immediate result of:
Lemma. Suppose p and q are numerals of base-Π-n such that p is obtainable from q by
interchanging two digits of q. Then p − q is a multiple of m.
2
Proof. Let
p = ct| . . . |c1|B|bs| . . . |b1|A|ar| . . . |a1
and
q = ct| . . . |c1|A|bs| . . . |b1|B|ar| . . . |a1.
Assume, without loss of generality, A < B. We let X = B − A − 1 and Y = 1|0 + A − B,
and perform the following:
ct| . . . |c1|B|bs| . . . |b1|A|ar| . . . |a1
−ct| . . . |c1|A|bs| . . . |b1|B|ar| . . . |a1
X| m | . . . | m |Y | 0 | . . . | 0
We show that X| 0| . . . |0
s
|Y | 0| . . . |0
r
is a multiple of m.
X| 0| . . . |0
s
|Y | 0| . . . |0
r
= X × 1|0s+r+1
+ Y × 1|0r
= (B − A − 1) × 1|0s+r+1
+ (1|0 + A − B) × 1|0r
= (B − A − 1) × 1|0s+1
− (B − A − 1|0) × 1|0r
= (B − A − 1) × 1|0s+1
− (B − A − 1 − m) × 1|0r
= (B − A − 1) × 1|0s+1
− (B − A − 1) + m × 1|0r
= (B − A − 1)(1|0s+1
− 1) + m × 1|0r
= (B − A − 1)(1|0 − 1)(1|0s
+ 1|0s−1
+ · · · + 1) + m × 1|0r
= (B − A − 1)m(1|0s
+ 1|0s−1
+ · · · + 1) + m × 1|0r
= m (B − A − 1)(1|0s
+ 1|0s−1
+ · · · + 1) + 1 × 1|0r
Thus, we arrive at:
Algorithm LP (Lexicographic Permutations). Given n, generates all permutations of
0, 1, . . . , n − 1 in lexicographic order.
LP1. Set x = 0|1| . . . |m, and i = 0.
LP2. Set pi = x.
LP3. If i = n! − 1, terminate.
LP4. Increase x by m.
LP5. If x has duplicate digits, go to LP4.
LP6. Increase i by 1 and go to LP2.
The following is a C99 implementation of the algorithm.
#include <stdio . h>
#include <s t d l i b . h>
void lexicographic permutations ( int n) // Given n , prints a l l
// permutations of
// 0 , 1 , . . . , n−1 as
3
// numerals of
// base−ten−n in order .
{
int x [ n ] , i , j , n fact , idx , dup digit ;
// Calculate n ! .
f or ( n fact = 1 , i = 2; i <= n ; ++i ) n fact ∗= i ;
// I n i t i a l i z e and print x .
f or ( i = 0; i <= n ; ++i )
i < n ? p r i n t f (”%d ” , x [ i ] = i ) : putchar ( ’n ’ ) ;
f or ( idx = 0; idx != n fact −1;)
{
// Add n−1 to x .
i f ( ! x [ n−1]) x [ n−1] = n−1;
e l s e
{
−−x [ n−1];
// Manage the carry .
f or ( i = n−2; i >= 0; −−i )
i f (x [ i ] == n−1) x [ i ] = 0;
e l s e
{
++x [ i ] ;
break ;
}
}
// Check fo r duplicate d i g i t s .
f or ( dup digit = 0 , i = 1; ! dup digit && i < n ; ++i )
f or ( j = i −1; ! dup digit && j >= 0; −−j )
i f (x [ j ] == x [ i ] ) ++dup digit ;
i f ( dup digit ) continue ;
// Print x .
f or ( i = 0; i <= n ; ++i )
i < n ? p r i n t f (”%d ” , x [ i ] ) : putchar ( ’n ’ ) ;
++idx ;
}
}
We can reduce calculations for the price of a relatively large array. Let di = pi+1 − pi for
i = 0, 1, . . . , n! − 2. Then
dn!−2 = pn!−1 − pn!−2 = p1 − p0 = d0
dn!−3 = pn!−2 − pn!−3 = p2 − p1 = d1
...
dn!
2
= pn!
2
+1 − pn!
2
= pn!
2
−1 − pn!
2
−2 = dn!
2
−2
dn!
2
−1 = pn!
2
− pn!
2
−1 = pn!
2
− pn!
2
−1 = dn!
2
−1.
4
Therefore, we can calculate d0, d1, . . . , dn!
2
−2, save them in an array, then use them to find
pn!
2
+1, pn!
2
+2, . . . , pn!−1.
5

A Numeric Algorithm for Generating Permutations in Lexicographic Order with a C Implementation

  • 1.
    A Numeric Algorithmfor Generating Permutations in Lexicographic Order with a C Implementation ©Afshin Tiraie November 20, 2012 While we use a positional numeral system, base-Π, given n arrangeable objects, we are required to produce all permutations of the objects in lexicographic order. Let 0, 1, · · · , m denote all numbers less than the number of the objects increasingly. Our goal is to derive a completely numeric algorithm (with no interchanges) for generating all permutations of 0, 1, · · · , m as numerals in order. Due to the logical correspondence between 0, 1, · · · , m and the objects, these permutations can be deemed those of the objects in lexicographic order. Decimal Index i pi Representation of pi − pi−1 0 0 1 2 1 0 2 1 2 2 1 0 2 4 3 1 2 0 4 4 2 0 1 4 5 2 1 0 2 Table 1: Base-ten-3 Permutations Let Π be ten. Then if n = 2, using base-two system, writing 1 as the first permutation of the digits of this system, 01, we can obtain the second permutation, 10, by adding 1 to 01. If n = 3, in base-three: 012 + 1 = 020, and 020 + 1 = 021. It is thus clear that using base-n system when n ≤ Π, we can easily achieve our goal. It is also clear, however, that when n > Π, base-n system cannot be considered. To overcome this difficulty, we define a numeral system founded on base-Π and n where: I. Each of base-Π numerals 0, 1, · · · , m, n, preserving its value is deemed a digit. II. A number is denoted by a sequence of digits with | between each pair of adjacent digits. 1
  • 2.
    III. |ar|ar−1| .. . |a0 represents the same number as ar × nr + ar−1 × nr−1 + · · · + a0 × n0 in base-Π. We call this system base-Π-n. Thus, 10|1|0|11 in base-two-100 represents the same number as the decimal 147(= 2×43 +42 +3). We omit bars when n ≤ Π; hence base-Π-10 and base-Π can be considered identical. We use p0, p1, · · · pn!−1 to represent permutations of 0, 1, · · · , m as numerals of base-Π-n in order. Decimal Index i pi Representation of pi − pi−1 0 0 1 2 3 1 0 1 3 2 3 2 0 2 1 3 9 3 0 2 3 1 6 4 0 3 1 2 9 5 0 3 2 1 3 6 1 0 2 3 18 7 1 0 3 2 3 8 1 2 0 3 21 9 1 2 3 0 9 10 1 3 0 2 6 11 1 3 2 0 6 12 2 0 1 3 15 13 2 0 3 1 6 14 2 1 0 3 6 15 2 1 3 0 9 16 2 3 0 1 21 17 2 3 1 0 3 18 3 0 1 2 18 19 3 0 2 1 3 20 3 1 0 2 9 21 3 1 2 0 6 22 3 2 0 1 9 23 3 2 1 0 3 Table 2: Base-ten-4 Permutations No matter how large n is, we can now calculate the permutations of base-Π-n. Tables 1 and 2 reveal: Proposition. The difference of any two permutations in base-Π-n is a multiple of n − 1. Since permutations are obtainable from one another through a sequence of transpositions, this proposition is an immediate result of: Lemma. Suppose p and q are numerals of base-Π-n such that p is obtainable from q by interchanging two digits of q. Then p − q is a multiple of m. 2
  • 3.
    Proof. Let p =ct| . . . |c1|B|bs| . . . |b1|A|ar| . . . |a1 and q = ct| . . . |c1|A|bs| . . . |b1|B|ar| . . . |a1. Assume, without loss of generality, A < B. We let X = B − A − 1 and Y = 1|0 + A − B, and perform the following: ct| . . . |c1|B|bs| . . . |b1|A|ar| . . . |a1 −ct| . . . |c1|A|bs| . . . |b1|B|ar| . . . |a1 X| m | . . . | m |Y | 0 | . . . | 0 We show that X| 0| . . . |0 s |Y | 0| . . . |0 r is a multiple of m. X| 0| . . . |0 s |Y | 0| . . . |0 r = X × 1|0s+r+1 + Y × 1|0r = (B − A − 1) × 1|0s+r+1 + (1|0 + A − B) × 1|0r = (B − A − 1) × 1|0s+1 − (B − A − 1|0) × 1|0r = (B − A − 1) × 1|0s+1 − (B − A − 1 − m) × 1|0r = (B − A − 1) × 1|0s+1 − (B − A − 1) + m × 1|0r = (B − A − 1)(1|0s+1 − 1) + m × 1|0r = (B − A − 1)(1|0 − 1)(1|0s + 1|0s−1 + · · · + 1) + m × 1|0r = (B − A − 1)m(1|0s + 1|0s−1 + · · · + 1) + m × 1|0r = m (B − A − 1)(1|0s + 1|0s−1 + · · · + 1) + 1 × 1|0r Thus, we arrive at: Algorithm LP (Lexicographic Permutations). Given n, generates all permutations of 0, 1, . . . , n − 1 in lexicographic order. LP1. Set x = 0|1| . . . |m, and i = 0. LP2. Set pi = x. LP3. If i = n! − 1, terminate. LP4. Increase x by m. LP5. If x has duplicate digits, go to LP4. LP6. Increase i by 1 and go to LP2. The following is a C99 implementation of the algorithm. #include <stdio . h> #include <s t d l i b . h> void lexicographic permutations ( int n) // Given n , prints a l l // permutations of // 0 , 1 , . . . , n−1 as 3
  • 4.
    // numerals of //base−ten−n in order . { int x [ n ] , i , j , n fact , idx , dup digit ; // Calculate n ! . f or ( n fact = 1 , i = 2; i <= n ; ++i ) n fact ∗= i ; // I n i t i a l i z e and print x . f or ( i = 0; i <= n ; ++i ) i < n ? p r i n t f (”%d ” , x [ i ] = i ) : putchar ( ’n ’ ) ; f or ( idx = 0; idx != n fact −1;) { // Add n−1 to x . i f ( ! x [ n−1]) x [ n−1] = n−1; e l s e { −−x [ n−1]; // Manage the carry . f or ( i = n−2; i >= 0; −−i ) i f (x [ i ] == n−1) x [ i ] = 0; e l s e { ++x [ i ] ; break ; } } // Check fo r duplicate d i g i t s . f or ( dup digit = 0 , i = 1; ! dup digit && i < n ; ++i ) f or ( j = i −1; ! dup digit && j >= 0; −−j ) i f (x [ j ] == x [ i ] ) ++dup digit ; i f ( dup digit ) continue ; // Print x . f or ( i = 0; i <= n ; ++i ) i < n ? p r i n t f (”%d ” , x [ i ] ) : putchar ( ’n ’ ) ; ++idx ; } } We can reduce calculations for the price of a relatively large array. Let di = pi+1 − pi for i = 0, 1, . . . , n! − 2. Then dn!−2 = pn!−1 − pn!−2 = p1 − p0 = d0 dn!−3 = pn!−2 − pn!−3 = p2 − p1 = d1 ... dn! 2 = pn! 2 +1 − pn! 2 = pn! 2 −1 − pn! 2 −2 = dn! 2 −2 dn! 2 −1 = pn! 2 − pn! 2 −1 = pn! 2 − pn! 2 −1 = dn! 2 −1. 4
  • 5.
    Therefore, we cancalculate d0, d1, . . . , dn! 2 −2, save them in an array, then use them to find pn! 2 +1, pn! 2 +2, . . . , pn!−1. 5