第一种方法字符串全排列,思想上和我们高中学的排列一样,比如123,开始的时候第一个位置有三种选择,第一个选完之后第二个位置就只剩下两种选择,第三个位置,就剩一种,所以一共有n!种排列,所以我们可以用递归的思想去做,递归中做交换
#include <stdio.h>
#include <stdlib.h>
#define MAX 50
void swap(char *a,char *b)
{
char tmp = *a;
*a = *b;
*b = tmp;
}
void permutations(char *str,int pos,int n) //pos表示当前位置,n表示字符串的大小
{
int i;
if(pos == n) //如果到最后,说明一次排列完毕,输出排列结果
{
for(i = 0; i <= n; i++)
printf("%c",str[i]);
printf("\n");
}
else
{
for(i = pos; i <= n; i++) //让此位置及以后的所有字符和它交换
{
swap(&str[pos],&str[i]);
permutations(str,pos+1,n); //递归进入下一个位置
swap(&str[pos],&str[i]); //返回的时候再交换回来
}
}
}
int main()
{
char str[MAX];
scanf("%s",str);
permutations(str,0,strlen(str)-1);
return 0;
}
第二种方法,使用字典序全排列,字典序就是按照从小到大的情况排列,比如有三位数123我们假设是百位 十位 个位则按照字典序排列的话,输出顺序为 123 132 213 231 312 321 ,也就是说,当前数的下一个数必须比它大,并且和它距离最短,这就是字典序排列。
算法描述:1.先将数组从小到大排序
2.从后往前扫描,找到ai<ai+1的位置,记下此时的i
3.从后往前扫描,找到第一个大于ai的数,比如ak
4.交换ai和ak 此时i+1到n排列是从大到小,所以要逆至,变成从小到大
5.将ai+1以后的数全部逆置,是为了让,变化后的数和上一个距离最短,把越大的数,放的越后,则变化范围最小,也就是二者想减,值最小
6.重复,2 3 4 5步骤,直到变成最大那个数为止
#include <stdio.h>
#include <stdlib.h>
#define MAX 50
void reverse(char *str,int i)
{
int n = strlen(str) - 1;
while(i < n)
{
char tmp = str[i];
str[i++] = str[n];
str[n--] = tmp;
}
}
int permutations(char *str,int n)
{
int i,j;
for(i = n-1; i >= 0 && str[i] >= str[i+1]; i--) //找到ai < ai+1的位置
{
}
if(i == -1)
return 0;
for(j = n; j >=0 && str[j] <= str[i]; j--) //找到最右边大于ai的数
{
}
char tmp = str[i];//交换i,j
str[i] = str[j];
str[j] = tmp;
reverse(str,i+1);//逆至i后面的数
return 1;
}
int main()
{
char str[MAX];
scanf("%s",str);
int n = strlen(str) - 1;
while(permutations(str,n))
printf("%s\n",str);
return 0;
}