序数法_字典法__邻位互换法_求解全排列

/************************************************************************/
/*   字典法求解全排列    */
/*    此方法可逆,即给出任何一个排列,比如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));
  }
 }
}
int 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->#@!.
*/

posted @ 2012-09-26 13:00  凡人修行  阅读(937)  评论(0)    收藏  举报