全排列--算法分析

最近我乱搞了一通。能力或知识有限。

/*全排列*/
/*较为复杂*/ 
#include<stdio.h>
#include<time.h>
void show(int a[],int n){
		for(int i=0;i<n;i++){
		printf("%d ",a[i]);
	}
	printf("\n"); 
}
void arrange(int a[],int n){
	int t=0;//辅助数组的长度 
	int b[n];//辅助数组 
	int state=0;//标识状态:1则结束 
	show(a,n);
	while(state==0){
	//从右向左扫描数组并处理 ,这是一趟处理. 
	for(int i=n-2;i>=0;i--){
		t=0;
		int flag=-1;
		if(a[i]<a[i+1]){/*若找到第一个比当前数大的数 */
			for(int j=0;j<n-i-1;j++){
				b[j]=a[n-1-j];
				t++;
				if(b[j]>a[i]&&flag==-1){//准备交换 
					flag=j;
				}
			}
			int tmp=b[flag];//交换 
			b[flag]=a[i];
			a[i]=tmp;
			for(int j=0;j<t;j++){//张贴 
				a[i+j+1]=b[j];
			}
			show(a,n);break;//打印 
		}	
	}
	for(t=0;t<n;t++){
		if(a[t]!=n-t)break;
	}if(t==n)state=1;
}
}
int main(){
	float start,end;
	int n=10;
	int a[n];
	for(int i=0;i<n;i++)a[i]=i+1;
	start=clock();
	arrange(a,n);
	end=clock();
	printf("\n\ntime: %f",end-start);
	return 0;
} 
/*算法正确性的证明: (数学归纳法)
	设N为1~N中的长度,
	当N=2时,由函数show(),
	"12"被打印,进入第二层循环--for,i指向1, 1<2,
	2人数组,12交换,打印"21",算法正确; 
	现假设当N=k时, 算法也正确,打印从
	"12...k"到"k(k-1)...1", 
	当N=k+1时,
	由N=k的假设,打印"12...k(k+1)"到
	"1(k+1)k...2", 还因为1后还不是k+1,在序列稍 
	右边至少存在一个比1大的数比k+1小,在 二层循环--for
	中,"a[i]<a[i+1]"的i指向的至少不是1,且只有当1后的
	数字序列逆序时,i才指向1。 接下来 进入第二层循环--for,
	i指向1,交换,"134...(k+1)"被顺序存入数组b[],张贴, 
	打印"2134...k(k+1)",......到"2(k+1)k...431",......
	不断地重复,"k(k+1)(k-1)(k-2)...1",..."(k+1)k(k-1)...1"
	结束,于是1~k+1的全排列就完成了。 
	综上所述,算法正确。 
*/ 
/*时间复杂性分析: 
	排列"123...N"到"1N(N-1)...2"为T(N-1),同理,
	 排列"213...N"到"2N(N-1)...431"为T(N-1),
	 ......
	  排列"N13...(N-2)(N-1)"到"N(N-1)...4321"为T(N-1),
	  共N个,有N*T(N-1); 
	从"1N(N-1)...2"到"2134...N", 
	从"2N(N-1)...431"到"3124...(N-1)N", 
	......
	从"(N-1)N(N-2)...21"到"N123...(N-2)(N-1)", 
	分别有N-1,又有N-1个,因此有(N-1)*(N-1); 
	再加上遍历打印和比较次数:N!*N+(1+2+3+...+N-1); 
	综上, 
	当N=2时,T(N)=1+0+4+1=6;
	当N>2时,T(N)=N*T(N-1)+(3*N-2)*(N-1)/2+N!*N; 
	由递推关系得,
	N>2时,T(N)=N!*[1+(7*2)/3!+(10*3)/4!+...+(3*N-2)*(N-1)/N!]/2; 
	(算错了,忘加N!*N了,但变化趋势应该差不多)
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值