全排列:
非递归算法:解题思路因为自己都讲不清楚。但觉得这位网友讲的不错把他的就直接引用了,至于代码我自己已经修改编译通过了!
题目:1~n的全排列
思想:(字典序法)初始化数组为1,2,3,...,n作为开端;设法从后续排列中找到大于前次结果但小于其他结果的序列;依此找出这样的序列(后面序列肯定大于前面序列),则最后一个序列肯定是n,...,3,2,1
步骤:
· 假设情景:找“*243”该序列的下一个后续序列
· 从后往前找,找到这样一个数,它后面的数更大,(即找到"*24*",取2作为当前数,下标为i)
· 在“2”的后面,找到最接近2且比2大的数,这里找到“3”(下标为j)
· 调换a[i]和a[j]的值
· 对a[i+1]……a[n-1]进行转置
· 此时数组a中的数就是所求后续序列
· 从1,2,3,...,n依此求出后续序列(即重新进行上面步骤),一直找到i=0且a[0]>a[1]则算法结束,全排列已全部给出。
三思:
· 怎么保证后面的序列比前面的大?首先开端是序列中最小的,i后面的部分是倒叙排列的,在对调(保证了大于前面序列)后,对i后面的进行逆置,保证了自身是后续排列中最小的,所以小于前面大于后面,依此递增,直到n,...,3,2,1算法结束。
· 该算法要给一个开端,对于求“142”全排列这种情况,是不是还需要进行先排序得到“124”后再处理?
· 该算法对调操作频繁,还有转置操作,相比较于递归调用函数,时间更少了,但心里不是滋味。
· 处理"1223"这种情况又怎样?递归方法不能处理,但这种方法可以处理。
· 对于字符排序"abc","abb"这两种情况,貌似与数字排序"123","122"一样,反正字符也可以比较大小,所以这两种情况也可以得到解决。
//全排列非递归算法
#include<stdio.h>
#define N 20
void Init_Arry(intarr[],int n); //初始化数组
void Print(intn); //输出排列
void Swap(inti,int j); //交换arr[i]和arr[j]的值
void Tranpose(intk,int m); //把数组脚标k到m的转置
int Full_Arry(int n); //对n个数进行全排列
int arr[N];
int count=0; //排列的个数
int main()
{
int n;
printf("\t全排列\n\n");
printf("输入数字的个数(1~20):\n");
scanf("%d",&n);
while(n>20||n<0)
{
printf("输入数字不合法,请重新输入(1~20):\n");
scanf("%d",&n);
}
Init_Arry(arr,n);
Full_Arry(n);
return 0;
}
//初始化数组
void Init_Arry(intarr[],int n)
{
int i;
for(i=1;i<=n;i++)
arr[i]=i;
}
//输出排列
void Print(int n)
{
int i;
count++;
printf("(%2d) ",count);
for(i=1;i<=n;i++)
printf("%d ",arr[i]);
printf("\n");
}
//交换arr[i]和arr[j]的值
void Swap(inti,int j)
{
int temp;
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
//把数组脚标k到m的转置
void Tranpose(intk,int m)
{
int i,j;
for(i=k,j=m;i<=(k+m)/2;j--,i++)
Swap(i,j);
}
//对n个数进行全排列
int Full_Arry(intn)
{
int i,j;
if(n==1) //n=1时
{
Print(n);
return 1;
}
else if(n==2)
{
printf("(1) %d%d\n",1,2);
printf("(2) %d%d\n",2,1);
return 1;
}
else
while(1)
{
Print(n);
for(i=n-1;i>=1;i--) //n必须大于等于2
{
if(arr[i]<arr[i+1]) //先求i
break;
if(i==1)
return 1; //函数出口:当i=1且arr[1]>arr[2]时,函数结束
}
for(j=n;j>i;j--) //后求j
{
if(arr[i]<arr[j]) //
break;
}
Swap(i,j); //调换arr[i]与arr[j]的值
Tranpose(i+1,n); //把i后面的数转置
}
}
递归的思路就不给出了;
//递归算法
//全排列递归算法
#include<stdio.h>
#define N20
voidInit_Arry(int arr[],int n); //初始化数组
voidarrange_all(int size, int arr[], int pos); //size 要排列的数据个数
//arr[] 排列存放的数组
//pos 当前排列位置
voidPrint(int n); //输出排列
intarr[N];
intcount=0; //排列的个数
intmain()
{
int n;
printf("\t全排列\n\n");
printf("输入数字的个数(1~20):\n");
scanf("%d",&n);
while(n>20||n<0)
{
printf("输入数字不合法,请重新输入(1~20):\n");
scanf("%d",&n);
}
Init_Arry(arr,n);
arrange_all(n, arr, 1);
return 0;
}
//初始化数组
voidInit_Arry(int arr[],int n)
{
int i;
for(i=1;i<=n;i++)
arr[i]=i;
}
//输出排列
voidPrint(int n)
{
int i;
count++;
printf("(%2d) ",count);
for(i=1;i<=n;i++)
printf("%d ",arr[i]);
printf("\n");
}
voidarrange_all(int size, int arr[], int pos)
{
inti, temp;
if (pos==size) //经排到最后
{
Print(size, arr);
}else
for (i=pos;i<=size; i++) // 对当前位置后的所有位置排列
{
temp = arr[pos]; // 交换位置
arr[pos] = arr[i];
arr[i] = temp;
// 递归继续后面的调用
arrange_all(size, arr, pos + 1);
// 在交换回来保持原有次序
temp = arr[pos];
arr[pos] = arr[i];
arr[i] = temp;
}
}
(算法代码参考互联网)
吴德妙 2011-11-26