输出一组数的全排列
全排列的初始思想:
假设一个数列为1,2,3,4,要求出该数列的全排列
1,2,3,4
首先保持第一个不变,对2,3,4进行全排列
再保持2不变,对3,4全排列‘
保持3不变对4进行全排列,4的排列只有一种。
之后3不再作为开头,3,4进行交换得到
1,2,4,3
此时,3,4的全排列写完,不再以2作为开头,得到
1,4,2,3
1,4,3,2
1,3,4,2
1,3,2,4
这样得到以1开头的所有全排列,再分别以2,3,4作为开头得到全排列。
可通过递归实现。
void swap(int *a, int*b)
{
int t = *a;
*a = *b;
*b = t;
}
void Allrange (int *a, int k, int n) //k为查找到第n个元素,n表示共有多少个数
{
int i;
if(k == n) //输出一个排列
{
for(i = 0; i < n; i++)
{
printf("%d\t",*a++);
}
else
{
for(i = k;i < n; i++)
{
swap(a + k, a + i); //交换
Allrange(a, k + 1, n);
swap(a + k, a + i); //换回交换前的值
}
}
}
以1——3为例,程序执行流程图
第一次不进行交换,输出原来的排序
第二次排序时才开始交换
去重全排列
例,对122,第一个数1与第二个数2交换得到212,然后考虑第一个数1与第三个数2交换,此时由于第三个数等于第二个数,所以第一个数不再与第三个数交换。再考虑212,它的第二个数与第三个数交换可以得到221.
即去重全排列规则:与非重复数字进行交换。
void isswap(int *a,int *b)
{
while(a!=b)
{
if(*a == *b)
return 0;
a++;
}
return 1;
}
给定任意字符串求其全排列
#include <stdio.h>
#include <string.h>
#define SWAP(x, y, t) ((t) = (x), (x) = (y), (y) = (t))
char list[100]; //定义全局变量
int isswap(int start, int end) //检查start-end之间有无重复值,有返回0, 无返回1
{
while (start < end) {
if (list[start] == list[end])
return 0; //false
start++;
}
return 1; //true
}
/*全排列的递归函数*/
void Allrange(int i, int n)
{
int j, temp;
if (n == i) //已经递归到最末项,直接输出
printf("%s\n", list);
else
{
for (j = i; j <= n; j++)
{
if (isswap(i, j)) //检查i--j之间有无重复值,一旦有,则直到后面重复处再去处理
{
SWAP(list[i], list[j], temp); //依次将i--j的字符换到i位置处作为头
Allrange(i+1, n); //将第i+1个位置后面的字符串求全排列,到此进入递归求解
SWAP(list[i], list[j], temp); //将交换过的字符再换回来
}
}
}
}
int main()
{
scanf("%s", list);
Allrange(0, strlen(list)-1);
printf("\n");
}