【字典序法生成全排列】
字典序列算法是一种非递归算法。而它正是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; }