字典序全排列

字典序法中,对于数字1、2、3......n的排列,不同排列的先后关系是从左到右逐个比较对应的数字的先后来决定的。例如对于5个数字的排列 12354和12345,排列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的下一个排列。
例如839647521是数字1~9的一个排列。从它生成下一个排列的步骤如下: 
自右至左找出排列中第一个比右边数字小的数字4          839647521
在该数字后的数字中找出比4大的数中最小的一个5        839647521
将5与4交换                                                                     839657421
将7421倒转                                                                     839651247

所以839647521的下一个排列是839651247。


给出程序:

#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");
}



  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值