序数法 字典法 邻位互换法 求解全排列 c语言 编程

/************************************************************************/
/* 字典法求解全排列 */
/* 此方法可逆,即给出任何一个排列,比如2413,我们可以按照字典排序计算 */
/*出下一个排序直至最后一个排列4321,然后在逆序,依次计算出2413的上一个排*/
/*序直至1234 */
/************************************************************************/
#define N 5 /*求解N阶全排列*/
int value[N];

void disp()
{/*打印值*/
int i;
static int count=0;
for (i=0;i<N;i++)
{
printf("%d",value[i]);
}
count++;
printf(" ");
if (count%6==0)
{
printf("\n");
}
}
void init()
{
int i;
for (i=0;i<N;i++)
{
value[i]=i+1;/*按照字典升序排列*/
}
}
int last_zx(const int a[],const int n)
{/*返回数组中最后一个正序的下标*/
int i;
int f;
for(i=0,f=-1;i<n;i++)
if (a[i]<a[i+1])
{
f=i;
}
return f;
}
int last_max(const int f,const int a[],int length)
{/*返回数组中大于a[f]的最后一个数下标*/
while(--length)
{
if (a[length]>a[f])
{
return length;
}
}
return -1;
}
int * swap_dx(int src,int dec,int a[],int length)
{/*交换a[src]和a[dec],并将下标从src+1到length-1的值逆序*/
int i,j;
a[src]+=a[dec];
a[dec]=a[src]-a[dec];
a[src]=a[src]-a[dec];
for(j=src+1,i=length-1;j<i;i--,j++)
{
a[i]+=a[j];
a[j]=a[i]-a[j];
a[i]=a[i]-a[j];
}
return a;
}
void fun()
{
int _last_zx;
int _last_max;
disp();
_last_zx=last_zx(value,N);
if (_last_zx==-1)
{
return;
}
else
{
_last_max=last_max(_last_zx,value,N);
swap_dx(_last_zx,_last_max,value,N);
fun();
}
}
void main(int argv,char *argc[])
{
init();
fun();
}








/************************************************************************/
/* 序数法求解全排列 */
/*该方法通过计算出N阶全排列的个数N!,然后依次求出0->N!的序列,根据该序列*/
/*产生出对应的新的排列,然后输出。 */
/************************************************************************/
#include <stdio.h>
#include <assert.h>
#define N 4 /*求N阶全排列*/
#define M 10 /*最多M+1阶求解*/
typedef unsigned long int uint;
int a[M];
void init()
{/*初始化数组*/
int i=0;
for(;i<M;i++)
a[i]=1;
}
void disp()
{/*打印数组*/
int i;
static int count=0;
printf("->");
for (i=M-N;i<M;i++)
{
printf("%d",a[i]);
a[i]=1;
}
printf(" ");
count++;
if (count%6==0)
{
printf("\n");
}
}
uint jc(uint n)
{/*返回n的阶乘值*/
uint value=1;
while(n)
{
value*=n--;
}
return value;
}
void xl(int const n)
{
int i=0;int temp=0;int v;int _n;
uint s=jc(n);/*计算出n的阶乘值*/
for(;i<s;i++)
{
v=i;
_n=n;
while(--_n>0)/*类似于进制数的短除法规则*/
{
printf("%d",v/(jc(_n)));
index(v/

(jc(_n)),_n+1);
v=v%(jc(_n));
}
}
}
i
nt index(int m,int n)
{/*查找n的插入位置,m表示全局数组a中数字n的位置到M-1位置中1的个数*/
int i=0;
int v=M-1;
int count=-1;
assert(v>=0);
while (v>0)
{
if (a[v]==1)
{
count++;/*从数组尾开始统计1的个数*/
}
if (count==m)/*找到n的位置*/
{
a[v]=n;/*将n插入其中*/
break;
}
v--;
}
if (n<=2)/*说明一个新的排列求解完毕,并打印出来*/
{
disp();
}
return 0;
}
int main(int arg,char *argv[])
{
init();
xl(N);
}







/************************************************************************/
/* 邻位互换法,求解全排列 */
/* */
/* 在此方法中,我们规定活动数为其箭头所指的邻位数小于该数,你也可以自 */
/*己定义一个方向和规则,但数的初始排列和方向必须对应起来。 */
/************************************************************************/

#define N 5 /*求N阶全排列*/
#include <stdio.h>
#include <assert.h>
#define RIGHT 1
#define LEFT -1
#define V(x) value[0][x] /*返回第x下标的值*/
#define F(x) value[1][x] /*返回第x下标的值的方向*/
int value[2][N]; /*value[0]行存值,value[1]行用于标识对应值的方向,这里规定1向右,-1向左*/

void disp()
{/*打印值*/
int i;
static int count=0;
for (i=0;i<N;i++)
{
printf("%d",V(i));
}
count++;
printf(" ");
if (count%6==0)
{
printf("\n");
}
}
void init()
{
int i;
for (i=0;i<N;i++)
{
F(i)=LEFT;/*初始方向设置为左*/
V(i)=i+1;
}
}
void adjust(const int v)
{
int i;
for (i=0;i<N;i++)
{
if(V(i)>v)
{
F(i)*=LEFT;/*将大于v的数方向反向*/
}
}
}
void fun()
{
int max_f=-1;
int i=0;
disp();
for(;i<N;i++)
{/*查找满足条件的最大数下标*/
if((i==0&&F(i)==LEFT)||(i==N-1&&F(i)==RIGHT))
continue;
if ((F(i)==RIGHT&&V(i)>V(i+1))||(F(i)==LEFT&&V(i)>V(i-1)))
{
if (max_f==-1)
{
max_f=i;
continue;
}
if (V(i)>V(max_f))
{
max_f=i;
}
}
}
if (max_f!=-1)
{
if (F(max_f)==RIGHT)
{
V(max_f)+=V(max_f+1);
V(max_f+1)=V(max_f)-V(max_f+1);
V(max_f)=V(max_f)-V(max_f+1);
F(max_f)+=F(max_f+1);
F(max_f+1)=F(max_f)-F(max_f+1);
F(max_f)=F(max_f)-F(max_f+1);
adjust(V(max_f+1));/*调整数组*/
}
else
{
V(max_f)+=V(max_f-1);
V(max_f-1)=V(max_f)-V(max_f-1);
V(max_f)=V(max_f)-V(max_f-1);
F(max_f)+=F(max_f-1);
F(max_f-1)=F(max_f)-F(max_f-1);
F(max_f)=F(max_f)-F(max_f-1);
adjust(V(max_f-1));/*调整数组*/
}
fun();/*重复此步骤*/
}
}
int main(int argv,char *argc[])
{
init();
fun();
return 0;
}



/*
总结:以上所有方法均可延伸为数组的下标排序,通过下标排序就可以求解任意字符之间的排列。
例如,求"!@#"字符串所有的全排列。那么就可以设a[1]='

;!',a[2]='@',a[3]='#',然后
对下标进行全排列
于是就有123->!@#,
132->!#@,
213->@!#,
231->@#!,
312->#!@,
321->#@!.
*/

相关文档
最新文档