問題:數字全排列,實作輸入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");
}
}
運作結果:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2csg3aq1UeRR1Ty0keYhnRzwEMW1mY1RzRapnTtxkb5ckYplTeMZTTINGMShUYfRHelRHLwEzX39GZhh2css2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xyayFWbyVGdhd3LcV2Zh1Wa9M3clN2byBXLzN3btg3Pn5GcuIDN5EzN1IjM0EjMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
方法二:
代碼如下:
#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;
//}
運作結果: