從字符串的第壹個數字idx=0開始,每次遞歸選擇s[idx]之後的壹個字符與s[idx]交換。
因為可能有重復的字符,所以可以使用哈希數組來標記當前循環中的每個字符是否被選中。
因為字符範圍不超過ASCII碼,所以壹個128空間的數組就足夠做標記了。
選擇當前字符s[i]並與s[idx]交換後,遞歸調用繼續排列下壹位s[idx+1]。
註意這裏需要回溯,也就是把選中的字符切換到s[idx]而不是s[i]。
所以要把之前的s[i]和s[idx]互換,恢復到原來的狀態,這樣才能循環判斷下壹個選擇。
具體代碼截圖如下:
運行結果如下:
結果正確,望采納~
附加源代碼:
# include & ltstdio.h & gt
# include & ltstdlib.h & gt
# include & ltstring.h & gt
#define MAXN 1000000 //排列總數可能很大。
int num = 0;//記錄排列總數
char * RES[MAXN]= { NULL };//指針數組保存排列結果。
Void swap(char *x,char *y) {//交換兩個字符變量的內容。
char ch = * x;
* x = * y;
* y = ch
}
Voidperm (char * s,int n,int idx){//回溯生成完整的字符串數組。
If (idx == n) {//已經排列在字符串的末尾。
RES[num]=(char *)malloc(sizeof(char)*(n+1));
//printf("%s\n ",s);//輸出當前排列
strcpy(res[num],s);//保存當前排列
num++;//排列總數加上1
返回;
}
int i,hash[128]= { 0 };//哈希數組,標記每個字符是否被選中。
for(I = idx;我& ltn;i++) {
if (hash[s[i]] == 1)
繼續;//跳過已標記的重復字符。
hash[s[I]]= 1;//如果選中,將在數組中標記為1。
互換(amps[idx],& amps[I]);//選擇s[i]切換到s[idx]
perm(s,n,idx+1);//遞歸地繼續選擇s[idx+1]
互換(amps[idx],& amps[I]);//返回,目前選擇其他字符而不是s[i]。
}
}
int main() {
int n,I;
scanf("%d ",& ampn);
char * s =(char *)malloc(sizeof(char)*(n+1));
scanf("%s ",s);
perm(s,n,0);
Printf("壹個* * *: \n "中有%d個排列),num);//輸出排列總數
for(I = 0;我& ltnumI++) {//輸出所有排列。
printf("%s\n ",RES[I]);
免費(RES[I]);//釋放內存空間
}
免費;
返回0;
}