Revision as of 00:04, 7 July 2015 editSverdrup (talk | contribs)Extended confirmed users8,936 edits This edit broke the algorithm -- undo to restore. Undid revision 670122498 by 120.56.132.183 (talk)← Previous edit | Latest revision as of 13:59, 6 January 2025 edit undoMarSch (talk | contribs)Extended confirmed users8,553 editsm →Details of the algorithm | ||
(217 intermediate revisions by more than 100 users not shown) | |||
Line 1: | Line 1: | ||
{{Short description|Method of generating all permutations of n objects}} | |||
'''Heap's algorithm''' is an ] used for generating all possible ]s of some given length. It was first proposed by B. R. Heap in 1963.<ref>{{cite journal|last=Heap|first=B. R.|title=Permutations by Interchanges|journal=The Computer Journal|year=1963|volume=6|issue=3|pages=293–4|url=http://comjnl.oxfordjournals.org/content/6/3/293.full.pdf|doi=10.1093/comjnl/6.3.293}}</ref> It generates each permutation from the previous one by choosing a pair of elements to interchange. In a 1977 review of permutation-generating algorithms, ] concluded that it was at that time the most effective algorithm for generating permutations by computer.<ref>{{cite doi|10.1145/356689.356692}}</ref> | |||
{{Distinguish|heapsort}} | |||
] | |||
] | |||
'''Heap's ]''' generates all possible ]s of {{math|''n''}} objects. It was first proposed by B. R. Heap in 1963.<ref name="Heap">{{cite journal|last=Heap|first=B. R.|title=Permutations by Interchanges|journal=The Computer Journal|year=1963|volume=6|issue=3|pages=293–4|doi=10.1093/comjnl/6.3.293|doi-access=free}}</ref> The algorithm minimizes movement: it generates each permutation from the previous one by interchanging a single pair of elements; the other {{math|''n''−2}} elements are not disturbed. In a 1977 review of permutation-generating algorithms, ] concluded that it was at that time the most effective algorithm for generating permutations by computer.<ref>{{Cite journal | last1 = Sedgewick | first1 = R. | title = Permutation Generation Methods | doi = 10.1145/356689.356692 | journal = ACM Computing Surveys | volume = 9 | issue = 2 | pages = 137–164| year = 1977 | s2cid = 12139332 | doi-access = free }}</ref> | |||
The ] of permutations of {{math|''n''}} objects generated by Heap's algorithm is the beginning of the sequence of permutations of {{math|''n''+1}} objects. So there is one infinite sequence of permutations generated by Heap's algorithm {{OEIS|A280318}}. | |||
== Details of the algorithm == | == Details of the algorithm == | ||
For a collection <math>C</math> containing {{math|''n''}} different elements, Heap found a systematic method for choosing at each step a pair of elements to switch in order to produce every possible permutation of these elements exactly once. | |||
Suppose we have a permutation containing ''N'' different elements. Heap found a systematic method for choosing at each step a pair of elements to switch, in order to produce every possible permutation of these elements exactly once. Let us describe Heap's method in a recursive way. First we set a counter ''i'' to 0. Now we perform the following steps repeatedly, until ''i'' is bigger than ''N''. We use the algorithm to generate the (''N'' − 1)<nowiki>!</nowiki> permutations of the first ''N'' − 1 elements, adjoining the last element to each of these. This generates all of the permutations that end with the last element. Then if ''N'' is odd, we switch the first element and the last one, while if ''N'' is even we can switch the ''i'' th element and the last one (there is no difference between ''N'' even and odd in the first iteration). We add one to the counter ''i'' and repeat. In each iteration, the algorithm will produce all of the permutations that end with the element that has just been moved to the "last" position. The following pseudocode outputs all permutations of a data array of length ''N''. | |||
Described recursively as a ] method, Heap's algorithm operates at each step on the <math>k</math> initial elements of the collection. Initially <math>k=n</math> and thereafter <math>k<n</math>. Each step generates the <math>k!</math> permutations that end with the same <math>n-k</math> final elements. It does this by calling itself once with the <math>k\text{th}</math> element unaltered and then <math>k-1</math> times with the (<math>k\text{th}</math>) element exchanged for each of the initial <math>k-1</math> elements. The recursive calls modify the initial <math>k-1</math> elements and a rule is needed at each iteration to select which will be exchanged with the last. Heap's method says that this choice can be made by the ] of the number of elements operated on at this step. If <math>k</math> is even, then the final element is iteratively exchanged with each element index. If <math>k</math> is odd, the final element is always exchanged with the first. | |||
<source lang="pascal"> | |||
procedure generate(n : integer, A : array of any): | |||
<syntaxhighlight lang="pascal"> | |||
if n = 1 then | |||
// Output the k! permutations of A in which the first k elements are permuted in all ways. | |||
output(A) | |||
// To get all permutations of A, use k := length of A. | |||
// | |||
// If, k > length of A, will try to access A out of bounds. | |||
// If k <= 0 there will be no output (empty array has no permutations) | |||
procedure permutations(k : integer, A : array of any): | |||
if k = 1 then | |||
output(A) | |||
else | else | ||
|
// permutations with last element fixed | ||
|
permutations(k - 1, A) | ||
|
// permutations with last element swapped out | ||
|
for i := 0; i < k-1; i += 1 do | ||
if k is even then | |||
swap(A, A) | |||
else | else | ||
swap(A, A) | swap(A, A) | ||
end if | |||
permutations(k - 1, A) | |||
end for | |||
end if | |||
</syntaxhighlight> | |||
One can also write the algorithm in a non-recursive format.<ref>{{cite web|last=Sedgewick|first=Robert|title=a talk on Permutation Generation Algorithms|date=4 June 2020 |url=https://sedgewick.io/wp-content/uploads/2022/03/2002PermGeneration.pdf}}</ref> | |||
<syntaxhighlight lang="pascal"> | |||
procedure permutations(n : integer, A : array of any): | |||
// c is an encoding of the stack state. | |||
// c encodes the for-loop counter for when permutations(k - 1, A) is called | |||
c : array of int | |||
for i := 0; i < n; i += 1 do | |||
c := 0 | |||
end for | |||
output(A) | |||
// i acts similarly to a stack pointer | |||
i := 1; | |||
while i < n do | |||
if c < i then | |||
if i is even then | |||
swap(A, A) | |||
else | |||
swap(A], A) | |||
end if | |||
output(A) | |||
// Swap has occurred ending the while-loop. Simulate the increment of the while-loop counter | |||
c += 1 | |||
// Simulate recursive call reaching the base case by bringing the pointer to the base case analog in the array | |||
i := 1 | |||
else | |||
// Calling permutations(i+1, A) has ended as the while-loop terminated. Reset the state and simulate popping the stack by incrementing the pointer. | |||
c := 0 | |||
i += 1 | |||
end if | |||
end while | |||
</syntaxhighlight> | |||
==Proof== | |||
In this proof, we'll use the below implementation as Heap's algorithm as it makes the analysis easier, and certain patterns can be easily illustrated. While it is not optimal (it does not minimize moves, which is described in the section below), the implementation is correct and will produce all permutations. | |||
<syntaxhighlight lang="pascal"> | |||
// Output the k! permutations of A in which the first k elements are permuted in all ways. | |||
// To get all permutations of A, use k := length of A. | |||
// | |||
// If, k > length of A, will try to access A out of bounds. | |||
// If k <= 0 there will be no output (empty array has no permutations) | |||
procedure permutations(k : integer, A : array of any): | |||
if k = 1 then | |||
output(A) | |||
else | |||
for i := 0; i < k; i += 1 do | |||
permutations(k - 1, A) | |||
if k is even then | |||
swap(A, A) | |||
else | |||
swap(A, A) | |||
end if | |||
end for | |||
end if | |||
</syntaxhighlight> | |||
Claim: If array A has length {{mvar|n}}, then <code>permutations(n, A)</code> will result in either A being unchanged, if {{mvar|n}} is odd, or, if {{mvar|n}} is even, then A is rotated to the right by 1 (last element shifted in front of other elements). | |||
Base: If array {{mvar|A}} has length 1, then <code>permutations(1, A)</code> will output A and stop, so A is unchanged. Since 1 is odd, this is what was claimed, so the claim is true for arrays of length 1. | |||
Induction: If the claim is true for arrays of length {{math|l}} ≥ 1, then we show that the claim is true for arrays of length {{math|l}}+1 (together with the base case this proves that the claim is true for arrays of all lengths). Since the claim depends on whether {{math|l}} is odd or even, we prove each case separately. | |||
If {{math|l}} is odd, then, by the induction hypothesis, for an array A of length {{math|l}}, <code>permutations(l, A)</code> will not change A, and for the claim to hold for arrays of length {{math|l}}+1 (which is even), we need to show that <code>permutations(l+1, A)</code> rotates A to the right by 1 position. Doing <code>permutations(l+1, A)</code> will first do <code>permutations(l, A)</code> (leaving A unchanged since {{math|l}} is odd) and then in each iteration {{math|i}} of the for-loop, swap the elements in positions {{math|i}} and {{math|l}} (the last position) in A. The first swap puts element {{math|l}} (the last element) in position 0, and element 0 in position {{math|l}}. The next swap puts the element in position {{math|l}} (where the previous iteration put original element 0) in position 1 and element 1 in position {{math|l}}. In the final iteration, the swap puts element {{math|l}}-1 is in position {{math|l}}, and the element in position {{math|l}} (where the previous iteration put original element {{math|l}}-2) in position {{math|l}}-1. To illustrate the above, look below for the case {{math|n}} = 4. | |||
<pre> | |||
1,2,3,4 ... original array | |||
1,2,3,4 ... 1st iteration (permute subarray) | |||
4,2,3,1 ... 1st iteration (swap 1st element into last position) | |||
4,2,3,1 ... 2nd iteration (permute subarray) | |||
4,1,3,2 ... 2nd iteration (swap 2nd element into last position) | |||
4,1,3,2 ... 3rd iteration (permute subarray) | |||
4,1,2,3 ... 3rd iteration (swap 3rd element into last position) | |||
4,1,2,3 ... 4th iteration (permute subarray) | |||
4,1,2,3 ... 4th iteration (swap 4th element into last position) | |||
The altered array is a rotated version of the original | |||
</pre> | |||
If {{math|l}} is even, then, by the induction hypothesis, for an array A of length {{math|l}}, <code>permutations(l, A)</code> rotates A to the right by 1 position, and for the claim to hold for arrays of length {{math|l}}+1 (which is odd), we need to show that <code>permutations(l+1, A)</code> leaves A unchanged. Doing <code>permutations(l+1, A)</code> will in each iteration {{math|i}} of the for-loop, first do <code>permutations(l, A)</code> (rotating the first {{math|l}} elements of A by 1 position since {{math|l}} is even) and then, swap the elements in positions 0 and {{math|l}} (the last position) in A. Rotating the first {{math|l}} elements and then swapping the first and last elements is equivalent to rotating the entire array. Since there are as many iterations of the loop as there are elements in the array, the entire array is rotated until each element returns to where it started. To illustrate the above, look below for the case {{math|n}} = 5. | |||
<pre> | |||
1,2,3,4,5 ... original array | |||
4,1,2,3,5 ... 1st iteration (permute subarray, which rotates it) | |||
5,1,2,3,4 ... 1st iteration (swap) | |||
3,5,1,2,4 ... 2nd iteration (permute subarray, which rotates it) | |||
4,5,1,2,3 ... 2nd iteration (swap) | |||
2,4,5,1,3 ... 3rd iteration (permute subarray, which rotates it) | |||
3,4,5,1,2 ... 3rd iteration (swap) | |||
1,3,4,5,2 ... 4th iteration (permute subarray, which rotates it) | |||
2,3,4,5,1 ... 4th iteration (swap) | |||
5,2,3,4,1 ... 5th iteration (permute subarray, which rotates it) | |||
1,2,3,4,5 ... 5th iteration (swap) | |||
The final state of the array is in the same order as the original | |||
</pre> | |||
The induction proof for the claim is now complete, which will now lead to why Heap's Algorithm creates all permutations of array {{mvar|A}}. Once again we will prove by induction the correctness of Heap's Algorithm. | |||
Basis: Heap's Algorithm trivially permutes an array {{mvar|A}} of size {{mvar|1}} as outputting {{mvar|A}} is the one and only permutation of {{mvar|A}}. | |||
Induction: Assume Heap's Algorithm permutes an array of size {{mvar|i}}. Using the results from the previous proof, every element of {{mvar|A}} will be in the "buffer" once when the first {{mvar|i}} elements are permuted. Because permutations of an array can be made by altering some array {{mvar|A}} through the removal of an element {{mvar|x}} from {{mvar|A}} then tacking on {{mvar|x}} to each permutation of the altered array, it follows that Heap's Algorithm permutes an array of size <math>i+1</math>, for the "buffer" in essence holds the removed element, being tacked onto the permutations of the subarray of size {{mvar|i}}. Because each iteration of Heap's Algorithm has a different element of {{mvar|A}} occupying the buffer when the subarray is permuted, every permutation is generated as each element of {{mvar|A}} has a chance to be tacked onto the permutations of the array {{mvar|A}} without the buffer element. | |||
==Frequent mis-implementations== | |||
It is tempting to simplify the recursive version given above by reducing the instances of recursive calls. For example, as: | |||
<syntaxhighlight lang="pascal"> | |||
procedure permutations(k : integer, A : array of any): | |||
if k = 1 then | |||
output(A) | |||
else | |||
// Recursively call once for each k | |||
for i := 0; i < k; i += 1 do | |||
permutations(k - 1, A) | |||
// swap choice dependent on parity of k (even or odd) | |||
if k is even then | |||
// no-op when i == k-1 | |||
swap(A, A) | |||
else | |||
// XXX incorrect additional swap when i==k-1 | |||
swap(A, A) | |||
end if | |||
end for | |||
end if | |||
</syntaxhighlight> | |||
This implementation will succeed in producing all permutations but does not minimize movement. As the recursive ] unwind, it results in additional swaps at each level. Half of these will be ] of <math>A</math> and <math>A</math> where <math>i==k-1</math> but when <math>k</math> is odd, it results in additional swaps of the <math>kth</math> with the <math>0th</math> element. | |||
{| class="wikitable" | |||
|- | |||
! <math>n</math> !! <math>n!-1</math> !! swaps !! additional = swaps <math>- (n!-1)</math> | |||
|- | |||
| 1 || 0 || 0 || 0 | |||
|- | |||
| 2 || 1 || 1 || 0 | |||
|- | |||
| 3 || 5 || 6 || 1 | |||
|- | |||
| 4 || 23 || 27 || 4 | |||
|- | |||
| 5 || 119 || 140 || 21 | |||
|- | |||
| 6 || 719 || 845 || 126 | |||
|- | |||
| 7 || 5039 || 5922 || 883 | |||
|- | |||
| 8 || 40319 || 47383 || 7064 | |||
|- | |||
| 9 || 362879 || 426456 || 63577 | |||
|- | |||
|} | |||
These additional swaps significantly alter the order of the <math>k-1</math> prefix elements. | |||
The additional swaps can be avoided by either adding an additional recursive call before the loop and looping <math>k-1</math> times (as above) '''or''' looping <math>k</math> times and checking that <math>i</math> is less than <math>k-1</math> as in: | |||
<syntaxhighlight lang="pascal"> | |||
procedure permutations(k : integer, A : array of any): | |||
if k = 1 then | |||
output(A) | |||
else | |||
// Recursively call once for each k | |||
for i := 0; i < k; i += 1 do | |||
permutations(k - 1, A) | |||
// avoid swap when i==k-1 | |||
if (i < k - 1) | |||
// swap choice dependent on parity of k | |||
if k is even then | |||
swap(A, A) | |||
else | |||
swap(A, A) | |||
end if | |||
end if | end if | ||
end for | end for | ||
generate(n - 1, A) | |||
end if | end if | ||
</syntaxhighlight> | |||
</source> | |||
The choice is primarily aesthetic but the latter results in checking the value of <math>i</math> twice as often. | |||
One could also write the algorithm in a non-recursive format.<ref>{{cite web|last=Sedgewick|first=Robert|title=a talk on Permutation Generation Algorithms|url=http://www.cs.princeton.edu/~rs/talks/perms.pdf}}</ref> | |||
==See also== | ==See also== |
Latest revision as of 13:59, 6 January 2025
Method of generating all permutations of n objects Not to be confused with heapsort.Heap's algorithm generates all possible permutations of n objects. It was first proposed by B. R. Heap in 1963. The algorithm minimizes movement: it generates each permutation from the previous one by interchanging a single pair of elements; the other n−2 elements are not disturbed. In a 1977 review of permutation-generating algorithms, Robert Sedgewick concluded that it was at that time the most effective algorithm for generating permutations by computer.
The sequence of permutations of n objects generated by Heap's algorithm is the beginning of the sequence of permutations of n+1 objects. So there is one infinite sequence of permutations generated by Heap's algorithm (sequence A280318 in the OEIS).
Details of the algorithm
For a collection containing n different elements, Heap found a systematic method for choosing at each step a pair of elements to switch in order to produce every possible permutation of these elements exactly once.
Described recursively as a decrease and conquer method, Heap's algorithm operates at each step on the initial elements of the collection. Initially and thereafter . Each step generates the permutations that end with the same final elements. It does this by calling itself once with the element unaltered and then times with the () element exchanged for each of the initial elements. The recursive calls modify the initial elements and a rule is needed at each iteration to select which will be exchanged with the last. Heap's method says that this choice can be made by the parity of the number of elements operated on at this step. If is even, then the final element is iteratively exchanged with each element index. If is odd, the final element is always exchanged with the first.
// Output the k! permutations of A in which the first k elements are permuted in all ways. // To get all permutations of A, use k := length of A. // // If, k > length of A, will try to access A out of bounds. // If k <= 0 there will be no output (empty array has no permutations) procedure permutations(k : integer, A : array of any): if k = 1 then output(A) else // permutations with last element fixed permutations(k - 1, A) // permutations with last element swapped out for i := 0; i < k-1; i += 1 do if k is even then swap(A, A) else swap(A, A) end if permutations(k - 1, A) end for end if
One can also write the algorithm in a non-recursive format.
procedure permutations(n : integer, A : array of any): // c is an encoding of the stack state. // c encodes the for-loop counter for when permutations(k - 1, A) is called c : array of int for i := 0; i < n; i += 1 do c := 0 end for output(A) // i acts similarly to a stack pointer i := 1; while i < n do if c < i then if i is even then swap(A, A) else swap(A], A) end if output(A) // Swap has occurred ending the while-loop. Simulate the increment of the while-loop counter c += 1 // Simulate recursive call reaching the base case by bringing the pointer to the base case analog in the array i := 1 else // Calling permutations(i+1, A) has ended as the while-loop terminated. Reset the state and simulate popping the stack by incrementing the pointer. c := 0 i += 1 end if end while
Proof
In this proof, we'll use the below implementation as Heap's algorithm as it makes the analysis easier, and certain patterns can be easily illustrated. While it is not optimal (it does not minimize moves, which is described in the section below), the implementation is correct and will produce all permutations.
// Output the k! permutations of A in which the first k elements are permuted in all ways. // To get all permutations of A, use k := length of A. // // If, k > length of A, will try to access A out of bounds. // If k <= 0 there will be no output (empty array has no permutations) procedure permutations(k : integer, A : array of any): if k = 1 then output(A) else for i := 0; i < k; i += 1 do permutations(k - 1, A) if k is even then swap(A, A) else swap(A, A) end if end for end if
Claim: If array A has length n, then permutations(n, A)
will result in either A being unchanged, if n is odd, or, if n is even, then A is rotated to the right by 1 (last element shifted in front of other elements).
Base: If array A has length 1, then permutations(1, A)
will output A and stop, so A is unchanged. Since 1 is odd, this is what was claimed, so the claim is true for arrays of length 1.
Induction: If the claim is true for arrays of length l ≥ 1, then we show that the claim is true for arrays of length l+1 (together with the base case this proves that the claim is true for arrays of all lengths). Since the claim depends on whether l is odd or even, we prove each case separately.
If l is odd, then, by the induction hypothesis, for an array A of length l, permutations(l, A)
will not change A, and for the claim to hold for arrays of length l+1 (which is even), we need to show that permutations(l+1, A)
rotates A to the right by 1 position. Doing permutations(l+1, A)
will first do permutations(l, A)
(leaving A unchanged since l is odd) and then in each iteration i of the for-loop, swap the elements in positions i and l (the last position) in A. The first swap puts element l (the last element) in position 0, and element 0 in position l. The next swap puts the element in position l (where the previous iteration put original element 0) in position 1 and element 1 in position l. In the final iteration, the swap puts element l-1 is in position l, and the element in position l (where the previous iteration put original element l-2) in position l-1. To illustrate the above, look below for the case n = 4.
1,2,3,4 ... original array 1,2,3,4 ... 1st iteration (permute subarray) 4,2,3,1 ... 1st iteration (swap 1st element into last position) 4,2,3,1 ... 2nd iteration (permute subarray) 4,1,3,2 ... 2nd iteration (swap 2nd element into last position) 4,1,3,2 ... 3rd iteration (permute subarray) 4,1,2,3 ... 3rd iteration (swap 3rd element into last position) 4,1,2,3 ... 4th iteration (permute subarray) 4,1,2,3 ... 4th iteration (swap 4th element into last position) The altered array is a rotated version of the original
If l is even, then, by the induction hypothesis, for an array A of length l, permutations(l, A)
rotates A to the right by 1 position, and for the claim to hold for arrays of length l+1 (which is odd), we need to show that permutations(l+1, A)
leaves A unchanged. Doing permutations(l+1, A)
will in each iteration i of the for-loop, first do permutations(l, A)
(rotating the first l elements of A by 1 position since l is even) and then, swap the elements in positions 0 and l (the last position) in A. Rotating the first l elements and then swapping the first and last elements is equivalent to rotating the entire array. Since there are as many iterations of the loop as there are elements in the array, the entire array is rotated until each element returns to where it started. To illustrate the above, look below for the case n = 5.
1,2,3,4,5 ... original array 4,1,2,3,5 ... 1st iteration (permute subarray, which rotates it) 5,1,2,3,4 ... 1st iteration (swap) 3,5,1,2,4 ... 2nd iteration (permute subarray, which rotates it) 4,5,1,2,3 ... 2nd iteration (swap) 2,4,5,1,3 ... 3rd iteration (permute subarray, which rotates it) 3,4,5,1,2 ... 3rd iteration (swap) 1,3,4,5,2 ... 4th iteration (permute subarray, which rotates it) 2,3,4,5,1 ... 4th iteration (swap) 5,2,3,4,1 ... 5th iteration (permute subarray, which rotates it) 1,2,3,4,5 ... 5th iteration (swap) The final state of the array is in the same order as the original
The induction proof for the claim is now complete, which will now lead to why Heap's Algorithm creates all permutations of array A. Once again we will prove by induction the correctness of Heap's Algorithm.
Basis: Heap's Algorithm trivially permutes an array A of size 1 as outputting A is the one and only permutation of A.
Induction: Assume Heap's Algorithm permutes an array of size i. Using the results from the previous proof, every element of A will be in the "buffer" once when the first i elements are permuted. Because permutations of an array can be made by altering some array A through the removal of an element x from A then tacking on x to each permutation of the altered array, it follows that Heap's Algorithm permutes an array of size , for the "buffer" in essence holds the removed element, being tacked onto the permutations of the subarray of size i. Because each iteration of Heap's Algorithm has a different element of A occupying the buffer when the subarray is permuted, every permutation is generated as each element of A has a chance to be tacked onto the permutations of the array A without the buffer element.
Frequent mis-implementations
It is tempting to simplify the recursive version given above by reducing the instances of recursive calls. For example, as:
procedure permutations(k : integer, A : array of any): if k = 1 then output(A) else // Recursively call once for each k for i := 0; i < k; i += 1 do permutations(k - 1, A) // swap choice dependent on parity of k (even or odd) if k is even then // no-op when i == k-1 swap(A, A) else // XXX incorrect additional swap when i==k-1 swap(A, A) end if end for end if
This implementation will succeed in producing all permutations but does not minimize movement. As the recursive call-stacks unwind, it results in additional swaps at each level. Half of these will be no-ops of and where but when is odd, it results in additional swaps of the with the element.
swaps | additional = swaps | ||
---|---|---|---|
1 | 0 | 0 | 0 |
2 | 1 | 1 | 0 |
3 | 5 | 6 | 1 |
4 | 23 | 27 | 4 |
5 | 119 | 140 | 21 |
6 | 719 | 845 | 126 |
7 | 5039 | 5922 | 883 |
8 | 40319 | 47383 | 7064 |
9 | 362879 | 426456 | 63577 |
These additional swaps significantly alter the order of the prefix elements.
The additional swaps can be avoided by either adding an additional recursive call before the loop and looping times (as above) or looping times and checking that is less than as in:
procedure permutations(k : integer, A : array of any): if k = 1 then output(A) else // Recursively call once for each k for i := 0; i < k; i += 1 do permutations(k - 1, A) // avoid swap when i==k-1 if (i < k - 1) // swap choice dependent on parity of k if k is even then swap(A, A) else swap(A, A) end if end if end for end if
The choice is primarily aesthetic but the latter results in checking the value of twice as often.
See also
References
- Heap, B. R. (1963). "Permutations by Interchanges". The Computer Journal. 6 (3): 293–4. doi:10.1093/comjnl/6.3.293.
- Sedgewick, R. (1977). "Permutation Generation Methods". ACM Computing Surveys. 9 (2): 137–164. doi:10.1145/356689.356692. S2CID 12139332.
- Sedgewick, Robert (4 June 2020). "a talk on Permutation Generation Algorithms" (PDF).