【字典序法生成全排列】
字典序列算法是一种非递归算法。而它正是STL中Next_permutation的实现算法。我们来看看他的思路吧:
它的整体思想是让排列成为可递推的数列,也就是说从前一状态的排列,可以推出一种新的状态,直到最终状态。比如说,最初状态是12345,最终状态是54321。其实我觉得这跟我们手动做全排列是一样的。首先是12345,然后12354,然后12435,12453....逐渐地从后往前递增。
看看算法描述:
首先,将待排序列变成有序(升序)序列。然后,从最后向前寻找,让相邻的两个元素比较大小 ,i = n-2,j=i+1,比较 Ti与Tj,如果没有找到 Ti<Tj,则说明整个序列已经是降序排列了,也就是说到达最终状态54321了。此时,全排列结束。
如果找到 Ti<Tj,记录i的大小也就是Ti的位置
然后,从数组最后向前找到第一个元素Tk,使得Tk>Ti(很多时候k=j),找到它,交换Ti跟Tk,并且将Tj到Tn-1(Tn-1是最后一个元素)的子序列进行倒置操作(也就是是Ti后面的序列全部进行翻转)。输出此序列。并回到第二步继续寻找i和k.
例如839647521是数字1~9的一个排列。从它生成下一个排列的步骤如下:
自右至左找出排列中第一个比右边数字小的数字4 839647521
在该数字后的数字中找出比4大的数中第一个数是5 839647521
将5与4交换 839657421
将7421倒转 839651247
所以839647521的下一个排列是839651247。
839651247的下一个排列是839651274。
这里边的重点或者说是中心思想应该是:
1:两次查找--->分别得到要交换的Ai和Ak
2:两次交换----->第一次是将Ai和Ak 交换位置;
第二次是将下标为i的后面的元素顺序进行翻转
代码如下:
#include <stdio.h>
#include <stdlib.h>
//function definition
void Swap(int &a,int &b);
void Reverse (int[],int,int);
void printArray (int[],int);
int nextPermutation(int[],int);
void Swap(int &a,int &b){
int tmp;
tmp=a;
a=b;
b=tmp;
}
void Reverse(int target[],int begin,int end){
while (begin<end){
Swap(target[begin],target[end]);
begin++;
end--;
}
}
//function implementation
int nextPermutation(int target[],int end){
int i =3,j =3;
for (i=end-1;i>=0;i--){
if (target[i]<target[i+1]) break;
}
if (i<0) return 0; //means the permutation is over
j=i+1;
int k;
for (k=end;target[k]<=target[i];k--);
Swap(target[i],target[k]);
Reverse(target,j,end);
return 1;
}
void printArray (int target[],int length){
int i;
for (i=0;i<length;i++) printf ("%d-",target[i]);
printf ("\n");
}
//test function
void testPermute(){
printf ("input a number:");
int n;
scanf ("%d",&n);
int i;
int * testcase = (int*)malloc(n*sizeof(int));
for (i=0;i<n;i++) testcase[i]=i+1;
printArray (testcase,n);
while (nextPermutation(testcase,n-1)){
printArray (testcase,n);
}
}
//main function
int main(){
testPermute();
system("pause");
return 0;
}