字典序算法

字典序排列就是按照字典a-z,1-9的顺序给出字符串的顺序全排列,例如abc的全排列就是从abc一直排到cba。那么给定一个字符串,怎么找出恰好大于该字符串的下一个排列呢?

我们考虑如下的步骤:

1、假设字符串为p1p2….pn,我们从后往前寻找第一个符合pj<pj+1条件的字符pj,也就是说,p1p2…pj-1pjpj+1…pn中pj<pj+1并且pj+1>pj+2>…pn

2、再次从后往前寻找第一个大于pj的字符pk,也就是说,p1p2pj-1pjpj+1…pk-1pkpk+1…pn中从后往前pk>pj并且pk+1,…pn<pj,可以看出pk也是比pj大的数中最小的一个,因为最差情况下k=j+1。

3、交换pj和pk,这样在p1p2…pj前j个字符变大了,pj放到原来pk的位置上同样符合pj+1>…pk-1>pj>pk+1…>pn

4、为了得到恰好大于该字符串的下一个排列,我们看到从j+1之后的字符串是降序排列的,我们将其翻转,就可以得到想要的结果了。

那么什么时候整个过程结束呢?当再也找不到符合条件的j时,说明当前的字符串已经是逆序的了,也就是字典序最大。

 
  1. #include <stdio.h>   
  2.   
  3. int a[10],N;  
  4.   
  5. int cmp(const void *a,const void *b)  
  6. {  
  7.     return *(int*)a-*(int*)b;  
  8. }  
  9. int fac();  
  10. void Fun();  
  11. void Reverse(int m,int n);  
  12. void Output();  
  13.   
  14. int main()  
  15. {  
  16.     int i;  
  17.     while (printf("\nPlease input N:  "),scanf("%d",&N)!=EOF)  
  18.     {  
  19.         printf("Please input %d numbers:\n",N);  
  20.         for (i=0;i<N;i++)  
  21.         {  
  22.             scanf("%d",&a[i]);  
  23.         }  
  24.         qsort(a,N,sizeof(a[0]),cmp);  //先将N个数排序   
  25.         printf("These numbers are:  \n");  
  26.         for (i=0;i<N;i++)  
  27.         {  
  28.             printf("%3d",a[i]);  
  29.         }  
  30.         printf("\n");  
  31.         Fun();  
  32.     }  
  33.     return 0;  
  34. }  
  35.   
  36. int fac()  //求N的阶乘,即全排列的个数   
  37. {  
  38.     int count=1,i=2;  
  39.     while (i<=N)  
  40.     {  
  41.         count*=i;  
  42.         i++;  
  43.     }  
  44.     return count;  
  45. }  
  46.   
  47. void Fun()  
  48. {  
  49.     int index1,index2,i,k,min,n,temp;  //index1为上述j下标,index2为上述k下标   
  50.     n=fac();  
  51.   
  52.     for (k=1;k<n;k++)    //n次循环   
  53.     {  
  54.         for (index1=N-2;index1>=0;index1--)    //求index1下标   
  55.         {  
  56.             if (a[index1]<a[index1+1])  
  57.             {  
  58.                 break;  
  59.             }  
  60.         }  
  61.   
  62.         min=32767;  
  63.         for (i=index1+1;i<N;i++)  //求index2   
  64.         {  
  65.             if (a[i]>a[index1])  
  66.             {  
  67.                 if (a[i]<min)  
  68.                 {  
  69.                     min=a[i];  
  70.                     index2=i;  
  71.                 }  
  72.             }  
  73.         }  
  74.         temp=a[index1];       //交换a[index1],a[index2]   
  75.         a[index1]=a[index2];  
  76.         a[index2]=temp;  
  77.   
  78.         Reverse(index1+1,N-1); //逆置a[index1]到a[N-1]的数   
  79.         Output();  //输出   
  80.     }   
  81. }  
  82.   
  83. void Reverse(int m,int n)  
  84. {  
  85.     int temp;  
  86.     while (m<n)  
  87.     {  
  88.         temp=a[m];  
  89.         a[m]=a[n];  
  90.         a[n]=temp;  
  91.         m++;  
  92.         n--;  
  93.     }  
  94. }  
  95.   
  96. void Output()  
  97. {  
  98.     int i;  
  99.     for (i=0;i<N;i++)  
  100.     {  
  101.         printf("%3d",a[i]);  
  102.     }  
  103.     printf("\n");  
  104. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值