天天看点

数字的全排列

问题:数字全排列,实现输入n位数,然后输出其所有的排列方式;

这道题是深入学习理解递归的典型题

递归思想:全排列可以理解为取出一个数,让剩下的数排列

剩下的数以此类推,直到最后一个数为止;

方法一:

代码如下:

#include <stdio.h>
#include <stdlib.h>
#define max 100
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
void sort(int a[],int n,int s,int r[],int m);
int main(int argc, char *argv[]) {
 int n,m[max],i;
 int r[max];
 printf("请输入待排列数字的个数:");
 scanf("%d",&n);
 if(n>100){
  printf("超出该程序排序的最大范围,输入错误;");
 }else{
  printf("请输入元素:"); 
  for(i=0;i<n;i++){
   scanf("%d",&m[i]);
  }
 sort(m,n,0,r,n); 
 }
 return 0;
}
void sort(int a[],int n,int s,int r[],int m){          //其中m表示排列数字的个数,整个递归过程不发生改变; 
              //其实条件中的s是r数组的下标,r[s]存储递归每次取出的那个元素; 
 int i,j;                 //开始在该行定义了l=0;错误;导致下边的第一个for循环在第二次循环时还保留第一次了的值,必须每次保证清零; 
 int flag=0;
 int b[max]; 
 for(i=0;i<n;i++){     //该循环将数组中的第i个元素存入数组r中;
  flag=1;     //确定函数的范围是否到达该输出的时候; 
  r[s]=a[i];
  int l=0; 
  for(j=0;j<n;j++){   //该循环的目的是将剩下的元素放入一个新数组中,方便下次递归运用; 
   if(i!=j){
    b[l]=a[j];
    l++;
   }
  }
  sort(b,n-1,s+1,r,m); 
 }
 if(flag==0){
  int k; 
  printf("\n");
  for(k=0;k<m;k++){
   printf("%d  ",r[k]);
  }
  printf("\n");
 } 
}
           

运行结果:

数字的全排列

方法二:

代码如下:

#include <stdio.h>
#include <stdlib.h>
#define MAX 100
void swap(int* a, int* b);
void perm(int str[], int m, int size);
int main(int argc, char *argv[]) {
    int a[3] = {1,2,3};
    perm(a,0,3);
    return 0;
}
/* 交换两个数据 */
void swap(int* a, int* b)
{
    int s = *a;
    *a = *b;
    *b = c;
}
/*递归思想:全排列可以理解为取出一个数,让剩下的数排列
剩下的数以此类推,直到最后一个数为止;
*/ 
void perm(int str[], int m, int size){                  
    int i = 0,j = 0;
    if(m == size){
        for(i = 0; i < size; i++){
            printf("%d ",str[i]);
        }
        printf("\n");
    }
    else{
        for(j = m;j < size; j++){
            swap(&str[j],&str[m]);
            perm(str,m+1,size);        //必须搞明白递归的栈机制原理! 
            swap(&str[j],&str[m]);
        }
    }
}

**前期在不运用递归的情况下思考出错的带代码如下**
//可能出发点有误,在代码的初期排列种类就不够! 
 /* run this program using the console pauser or add your own getch, system("pause") or input loop */
 //数字全排列问题:就是将数字进行所有种类的组合,然后输出到屏幕上。组合不可以有重复的;例如123的六种组合方式;
 /*思考:1,个人认为这是一个很有含量的题,入手点不知从何处下手;
         2,感觉这类题目指针更容易解决;
         3,其中指针指一指向数列的最后一位,指针二指向倒数第二位,指针二依次前移与指针一交换数据;数列遍历一次;
   4,指针一前移一位,指针二同样指向指针一的前一位,然后再次像步骤3遍历.依次循环。
   5,这样的思考有一个缺点就是可能存在相同的数据,这样交换完数据依然没变,相当于我们数学中不需要变换。因此在交换的过程中需要加入判断! 
            问题一:就是地址的数据交换完不回归原来的数据,所以必须有一步就是回归原来的数组;
      问题二:这样交换位置后输出的全部仅仅是全排后的一部分,还有剩下一部分没有排列; 
      重新思考后:
        依照刚才的方法:剩余的排序发现刚好是顺序排列前后递减后的顺序,比如:123,剩下的部分就是231,312; 
    */ 
  //void swap(int *,int *); 
  //int main(int argc, char *argv[]) {
  // int a[MAX];
  // int s[MAX];              //先定义一个较大的数组,这个数组用于存放输入的数列,也就规定了排序的数列的长度最大为100;
  // int i,j,k,f,m,n;
  // int *p,*q;
  // printf("请输入需排序的数列的长度:"); 
  // scanf("%d",&n);
  //  if(n>100){
  //   printf("该数列长度超出了该函数的功能范围;"); 
  //  }else{
  //   
  //   for(i=0;i<n;i++){                    //输入数据,同时用另外一个变量存储数据; 
  //   scanf("%d ",&a[i]);
  //   s[i]=a[i];
  //  }
  //  printf("\n");
  //
  //  printf("输出全排后的数列:\n");
  //  for(f=0;f<n;f++){                        //输出为排序的数列; 
  //   printf("%d ",a[f]);
  //  }
  //  printf("\n");
  //  
  //  for(m=n-1;m>0;m--){                             //实现了思考的第2步; 
  //   p=&a[m]; 
  //   for(j=m-1;j>=0;j--){ 
  //    q=&a[j];
  //    swap(p,q);                        //实现了思考的第3步; 
  //    for(k=0;k<n;k++){
  //     printf("%d ",a[k]);
  //     a[k]=s[k];                           //数据回归原来的数组; 
  //    }
  //    printf("\n");  
  //   }
  //  }
  ///*现在需要实现“重新思考后”的问题 ; 
  // 感觉写一个方法对于解题更容易; 
  //*/ 
  //  int l,l_1,h;
  //  for(l=0;l<n;l++){
  //   h=a[n-1];
  //   a[l+1]=a[l];
  //   a[l+1]=s[l+1];
  //  }
  //  a[0]=a[n-1];
  //
  //   for(l_1=0;l_1<n;l_1++){
  //    printf("%d ",a[l_1]);
  //  }
  //
  // 
  // } 
  // return 0;
  //}
  //
  //void swap(int *a,int *b){                        //数据交换函数; 
  // int m;
  // m=*a;
  // *a=*b;
  // *b=m;
  //}
           

运行结果:

数字的全排列