字典序法
字典序法中,对于数组1, 2, 3.....n的排列, 不同排列的先后顺序是从左到右逐个比较对应的数字的先后来决定的。例如,对于5个数字的排列12354和12345,排列12345在前,12354在后, 按照这样的规定,5个数字中排列在最前面的是12345, 排在最后面的事54321。
字典序算法思想如下:
设P是1~n的一个全排列, p = p1p2......pn = p1p2.....pj-1pjpj+1.....pk-1pkpk+1....pn。
(1)从排列的右端开始, 找出第一个比右边数字小的数字序号j ( j从左端开始计算), 即 j = max{ i | pi < pi+1 }。
(2)在 pj 右边的数字中,找出所有比 pj 大的数中最小的数 pk , 即 k = max{ i | pi > pj } (右边的数从右自左是递增的,因此 k 是所有大于 pj 的数字中序号最大者)
(3) 对换 pi , pk 。
(4) 再将 pj+1.....pk-1pkpk+1...pn 倒转得到排列 pn = p1p2.....pj-1pjpn....pk+1pkpk-1....pj+1 , 这就是排列 p 的下一个排列。
例如:
839647521 是数字 1~9 的一个排列。
从它生成下一个排列的步骤如下:
(1)自右至左找出排列中第一个比右边小的数字4 8396 4 7521
(2)在该数字后的数字中找出比4大的数中最小的一个数5 8396 4 7 5 21
(3)将 5 与 4 交换 8396 5 74 21
(4)再将 7421 倒转 8396 5 12 4 7
这样就获得了839647521的下一个排列 83965124 7
源代码如下
#include<iostream>
#include<algorithm>
using namespace std;
void dict(int p[], int n);
void outp(int p[], int n);
int main()
{
int length;
cin>>length;
int p[9] = {
0, 1, 2, 3, 4, 5, 6, 7, 8
};
dict(p, length);
return 0;
}
void dict(int p[], int n)
{
int i, j;
outp(p, n);
i = n - 1;
while(i > 0)
{
if(p[i] < p[i+1])
{
for(j = n; j >= i+1; j--)
{
if(p[i] <= p[j])
{
break;
}
}
swap(p[i], p[j]);
for(j = n; j >= 1; j--)
{
i += 1;
if(i >= j) break;
swap(p[i], p[j]);
}
outp(p, n);
i = n;
}
i -= 1;
}
}
void outp(int p[], int n)
{
int i;
for(i = 1; i <= n; i++)
{
cout<<p[i]<<" ";
}
cout<<endl;
}