這篇博文先考慮簡單的數字的情況,如果輸入數字4,即輸出所有1-4組成的序列,
爲了熟悉回溯算法,因爲本人一直都不太熟悉回溯算法。。。所以還是特地記一下blog吧,
先上圖1:
注意到紅線的走向即爲回溯算法的走向。
上一下代碼,下面再作分析:
#include <stdio.h> #define MAX 10 int flags[MAX]; int datas[MAX]; int n; void print(void); void huisu(int step); int main(void){ printf("Input a num < 10 :\n"); scanf("%d",&n); huisu(0); return 0; } void print(){ int i; for(i=0; i<n;i++){ printf("%d ",datas[i]); } printf("\n"); } void huisu(int step){ int i; if(step==n) print(); else{ for(i=0; i<n;i++){ if(!flags[i]){ flags[i] = 1; datas[step] = i+1; huisu(step+1); flags[i] = 0; } } } }
flags數組用於判斷該數字是否訪問過,如果訪問過即繼續尋找未訪問的flags,
當step==N(如題目一開始提到的N=4),即已經到達4個數字,即已經找到一個序列輸出,否則回溯
下面的圖爲代碼分析圖:
注意到步驟6爲第一次回溯,此時前面的datas[0]=1,datas[1]=2並沒有發生改變。
for循環上一次只走到i=2這個步驟。當回溯到huisu(3)時,繼續執行flags[2]=0並且繼續走for循環,i++到達i=3的位置,這時flags[3]=1訪問過,datas[2]=4,huisu(3)要求for循環再找未被訪問的flags,找到flags[2]=1,此時step爲3,datas[3]=4併到huisu(4)輸出。
作了簡單的修改,使其可以支持任意字符的全序列排序:
#include <stdio.h> #define MAX 10 int flags[MAX]; char result[MAX]; char first[MAX]; int n; void print(void); void huisu(int step); int main(void){ int i; printf("Input a num < 10 :\n"); scanf("%d",&n); getchar();//****獲得序列中的換行符 for(i=0;i<n;i++) scanf("%c",&result[i]);//**** for(i=0;i<n;i++) first[i]=result[i];//**** huisu(0); return 0; } void print(){ int i; for(i=0; i<n;i++){ printf("%c ",result[i]);//**** } printf("\n"); } void huisu(int step){ int i; if(step==n) print(); else{ for(i=0; i<n;i++){ if(!flags[i]){ flags[i] = 1; result[step] = first[i];//****first存放一開始的字符數組 huisu(step+1); flags[i] = 0; } } } }
帶有//****字樣的爲修改部分。由數字的全序列裏面對datas[step]=i+1進行啓發,進行1-4的排序,如果改爲datas[step]=i即爲進行0-3的排序,對應任意字符數組中的下表0-3的任意排序。記得需要注意的是result對應的爲step(每一步都對應有其result值),需要回溯的爲step+1,其餘都爲改變i