字典序法中,对数字1、2、3.....n的排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列12345和12354,排列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
3)对换pj,pk
4)再将pj+1....pk-1pkpk+1pn逆转得到排列p'=p1p2...pj-1pjpn...pk+1pkpk-1...pj+1,这就是排列p的下一个排列。
例如21379854是数字1~9的一个排列。从它生成下一个排列的步骤如下:
1)“自右至左”找出排列中第一个比右边数字小的数字:7
2)在该数字后的数字中找到比7大的数中最小的一个:8
3)将7和8交换:21389754
4)将9754逆转:21384579
所以21379854的下一个排列是21384579
#include <stdio.h>
int a[10],N;
int cmp(const void *a,const void *b)
{
return *(int*)a-*(int*)b;
}
int fac();
void Fun();
void Reverse(int m,int n);
void Output();
int main()
{
int i;
while (printf("\nPlease input N: "),scanf("%d",&N)!=EOF)
{
printf("Please input %d numbers:\n",N);
for (i=0;i<N;i++)
{
scanf("%d",&a[i]);
}
qsort(a,N,sizeof(a[0]),cmp); //先将N个数排序
printf("These numbers are: \n");
for (i=0;i<N;i++)
{
printf("%3d",a[i]);
}
printf("\n");
Fun();
}
return 0;
}
int fac() //求N的阶乘,即全排列的个数
{
int count=1,i=2;
while (i<=N)
{
count*=i;
i++;
}
return count;
}
void Fun()
{
int index1,index2,i,k,min,n,temp; //index1为上述j下标,index2为上述k下标
n=fac();
for (k=1;k<n;k++) //n次循环
{
for (index1=N-2;index1>=0;index1--) //求index1下标
{
if (a[index1]<a[index1+1])
{
break;
}
}
min=32767;
for (i=index1+1;i<N;i++) //求index2
{
if (a[i]>a[index1])
{
if (a[i]<min)
{
min=a[i];
index2=i;
}
}
}
temp=a[index1]; //交换a[index1],a[index2]
a[index1]=a[index2];
a[index2]=temp;
Reverse(index1+1,N-1); //逆置a[index1]到a[N-1]的数
Output(); //输出
}
}
void Reverse(int m,int n)
{
int temp;
while (m<n)
{
temp=a[m];
a[m]=a[n];
a[n]=temp;
m++;
n--;
}
}
void Output()
{
int i;
for (i=0;i<N;i++)
{
printf("%3d",a[i]);
}
printf("\n");
}