字典序:生成下一个排列
用字典序生成排列,一个排列若按字典序,可以设计如下的树,例如N=4,根结点有4个子树,按顺序将这四个树的结点值排好。每个子树又有3个子树,其结点的值是父结点所不含有的那些值。直到将N层建好,则依次就是字典序的排列。
按照字典序的规则,已知一个N的排列 \( p_1,p_2,…p_N \),求下一个排列的算法如下描述:
STEP 1. 求符合 \( p_{j-1} < p_j \) 的j的最大值,记为i
STEP 2. 求符合 \( p_{i-1}<p_k \)的k的最大值,记为h
STEP 3. \( p_{i-1} \)与 \( p_{h} \)互换
STEP 4. 将互换后序列的\(p_i\)到\(p_N\)逆转,便得到下一个序列。
以N=4,序列\( (3,4,2,1) \)为例, \( p_{j-1} < p_j \) 的最大值为i=2, \( p_1<p_k \) 的k的最大值h=2。将p[1]与p[2]互换,并将p[2]到p[4]逆序,则得 \( (4,1,2,3) \)
若要生成N的全排列,可以从 \( (1,2,…,N) \) 开始,反复使用求下一个排列的方法,直到不存在 \( p_{j-1} < p_{j} \) 为止
#include <cstdio> #include <cstring> #define MAXN 30 void swap(char *s,int x,int y) { char tmp = s[x]; s[x] = s[y]; s[y] = tmp; } void reverse(char *s,int lwbd,int upbd) { int i; for(i=0;i<(upbd-lwbd)/2;i++) { swap(s,lwbd+i,upbd-i); } } int next_arrange(char* p,int N) { int k,i=-1,h; for(k=N;k>1;k--) { if(p[k-1]<p[k]) { i=k; break; } } if(i==-1) return 0; for(k=N;k>1;k--) { if(p[i-1]<p[k]) { h=k; break; } } swap(p,i-1,h); reverse(p,i,N); return 1; } int main(void) { int i,h,k,N; char p[MAXN]; scanf("%d",&N); for(k=1;k<=N;k++) { p[k]=k; } while(1) { int status = next_arrange(p,N); if(status==0) break; for(k=1;p[k];k++) { printf("%d",p[k]); } printf("\n"); } return 0; }