最近我乱搞了一通。能力或知识有限。
/*全排列*/
/*较为复杂*/
#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了,但变化趋势应该差不多)
*/