记得12年校赛时我们遇到的一道关于排列的问题,那个题目当时我绞尽脑汁都没想出来,当然现在还是不能写出来。但是那是我心中永远的一道坎啊。今天终于有时间再把它翻出来,彻底的把它解决掉。是一个关于排列的问题。我想了半天还是不能相出解决的办法,于是上网查了下关于字符或者数字全排列的问题,通用的解法是用递归的方法,看起来非常简单,但是能真正弄明白又没那么容易。通过百度,看到一个人提到一本书《C语言的科学与艺术》,说这本书里面有讲到关于全排列的问题。于是下了这本书。看了下,这本书还是非常好的。至少讲用递归全排列这个问题名称清楚。 于是我把它再实现一次,而且是封装好的。好让以后用到的时候直接调用吧。
解决N个不同字符全排列的问题,我们可以从递归的角度来思考,不断把问题简化。要实现ABCD的全排列,我们可以这样:
A+{BCD}的全排列
B+{ACD}的全排列
C+{ABD}的全排列
D+{ABC}的全排列
然后用相同的方法递归求后门字符串的全排列,这样就能够把问题解决了。具体的看代码吧。
void SwapStr(char *str,int k,int i) { char tmp; tmp = str[k]; str[k] = str[i]; str[i] = tmp; } static void PermuteWithFixedPrefix(char *str,int k) { //前K个字符不变,求剩下的字符的全排列 int i; if (k == strlen(str)) { printf("%s\n",str); } else { for (i = k; i < strlen(str); i++) { SwapStr(str,k,i); PermuteWithFixedPrefix(str,k+1); SwapStr(str,k,i); //重新交换K和i位置的字符 } } } static void ListPermutations(char *str) { PermuteWithFixedPrefix(str,0); }
字符串里面含有相同字符的情况下,那么我们再每次交换之前,先判断交换的字符是否在前面已经出显过,如果出现过了,就不再交换了。也就多加一个判断函数。
void SwapStr(char *str,int k,int i) { char tmp; tmp = str[k]; str[k] = str[i]; str[i] = tmp; } int IsSwap(char *str,int k,int i) { //return 1 表示不交换 //return 2 表示交换 int j; for (j = k; j < i; j++) { if (str[j] == str[i]) { return 0; } } return 1; } static void PermuteWithFixedPrefix(char *str,int k) { //前K个字符不变,求剩下的字符的全排列 int i,j,nFlg; if (k == strlen(str)) { printf("%s\n",str); } else { for (i = k; i < strlen(str); i++) { if (IsSwap(str,k,i)) { SwapStr(str,k,i); PermuteWithFixedPrefix(str,k+1); SwapStr(str,k,i); //重新交换K和i位置的字符 } } } } static void ListPermutations(char *str) { PermuteWithFixedPrefix(str,0); }