天天看點

數字的全排列

問題:數字全排列,實作輸入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;
  //}
           

運作結果:

數字的全排列