假设我们正在讨论置换值的字典顺序,您可以使用两种通用方法:
- 将元素的一个排列转换为下一个排列(如 ShreevatsaR 发布的),或
- 直接计算
n
th 排列,同时n
从 0 向上计数。
对于那些(像我一样;-)不说 C++ 作为本地人的人,方法 1 可以从以下伪代码实现,假设“左侧”索引为零的数组从零开始索引(替换一些其他结构,例如列表,“留作练习”;-):
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
下面是一个从 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
对于第二种方法(直接计算th 排列),请记住元素n
存在N!
排列。N
因此,如果要排列N
元素,则第一个(N-1)!
排列必须从最小的元素开始,下一个(N-1)!
排列必须从第二小的元素开始,依此类推。这导致了以下递归方法(再次在伪代码中,从 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
因此,例如,ABCD 的第 13 次排列如下所示:
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
顺便说一句,元素的“删除”可以由一个并行的布尔数组表示,它指示哪些元素仍然可用,因此没有必要在每次递归调用时创建一个新数组。
因此,要遍历 ABCD 的排列,只需从 0 数到 23 (4!-1) 并直接计算相应的排列。