一、非递归方法(字典序法)
这种算法用在C++的STL库中
对给定的字符集中的字符规定了一个先后顺序,在此基础上规定两个全排列的先后是从左到右逐个比较字符的先后顺序
[例]字符集{
1
,
2
,
3
},较小的数字较先,这样按字典序生成的全排列是:
123
,
132
,
213
,
231
,
312
,
321
※ 一个全排列可看做一个字符串,字符串可有
前缀
、
后缀
。
生成给定全排列的下一个排列.所谓
一个的下一个
就是这一个与下一个之间
没有其他的
。这就要求这一个与下一个有尽可能
长
的
共同前缀
,也即变化限制在尽可能
短
的
后缀
上。
[例]839647521是1--9的排列。
1
—9的排列最前面的是123456789,最后面的987654321,从右向左扫描若都是增的,就到了987654321,也就没有下一个了。否则找出第一次出现下降的位置。
【例】 如何得到346987521的下一个
1
,从尾部往前找第一个P(i-
1
) < P(i)的位置
3
4
6
<-
9
<-
8
<-
7
<-
5
<-
2
<-
1
最终找到6是第一个变小的数字,记录下6的位置i-
1
2
,从i位置往后找到最后一个大于6的数
3
4
6
->
9
->
8
->
7
5
2
1
最终找到7的位置,记录位置为m
3
,交换位置i-1和m的值
3
4
7
9
8
6
5
2
1
4
,倒序i位置后的所有数据
3
4
7
1
2
5
6
8
9
则347125689为346987521的下一个排列
代码:
private
static
void
PermutationList() {
int
fromIndex, endIndex, changeIndex; Sort(
0
, length -
1
);
do
{
// 输出一种全排列
Output(); fromIndex
= endIndex = length -
1
;
// 向前查找第一个变小的元素
while
(fromIndex >
0
&& words[fromIndex] < words[fromIndex -
1
]) --
fromIndex; changeIndex
=
fromIndex;
if
(fromIndex ==
0
)
break
;
// 向后查找最后一个大于words[fromIndex-1]的元素
while
(changeIndex +
1
< length && words[changeIndex +
1
] > words[fromIndex -
1
]) ++
changeIndex; Swap(fromIndex
-
1
, changeIndex);
// 交换两个值
InvertArray(fromIndex, endIndex);
// 对后面的所有值进行反向处理
}
while
(
true
); }
递归方法求全排列
递归方法很容易理解:分别将每个位置交换到最前面位,之后全排列剩下的位。
///
<summary>
///
递归方式生成全排列的方法
///
</summary>
///
<param name="fromIndex">
全排列的起始位置
</param>
///
<param name="endIndex">
全排列的终止位置
</param>
private
static
void
PermutationList(
int
fromIndex,
int
endIndex) {
if
(fromIndex ==
endIndex) Output();
else
{
for
(
int
index = fromIndex; index <= endIndex; ++
index) {
// 此处排序主要是为了生成字典序全排列,否则递归会打乱字典序
Sort(fromIndex, endIndex); Swap(fromIndex, index); PermutationList(fromIndex
+
1
, endIndex); Swap(fromIndex, index); } } }