当前位置:文档之家› 补充全排列算法C语言实现

补充全排列算法C语言实现

字符串全排列算法C语言实现
问题描述:
输入一个字符串,打印出该字符串中字符的所有排列。

输入:
123
输出:
123
132
213
231
312
321
问题分析:
现象分析:
这种问题,从直观感觉就是用递归方法来实现即:把复杂问题逐渐简单化,进而得出具体代码实现。

(如何发现一个问题可以使用递归方式来解决?经分析可以发现:M 个数的排列方法与N(N>M)个数的排列方法没有区别,处理方法与数据的个数没有关系。

处理方法的一致性,就可以采用递归)。

3个数(123)排列,第一位1不动,剩下两个数(23)的排列,只要相互颠倒一下,就可以出现关于1开头的所有排列 123 132
把2换到第一位,保持不动,剩下的两个数(13)的排列,只要相互颠倒一下,就可以出现关于2开头的所有排列 213 231
同理,把3换到第一位,可得到 312 321
扩展:
把3个数的所有排列,前面加一个4,就可以得到关于4开头的所有的排列4123
4132
4213
4231
4312
4321
若把4与后续数据中的任意一个数据交换,通过完成对后续三个数的全排列,就可以得到相应的数开头的四数的排列。

总结:
对4个数的排列,可以转换成首位不动,完成对3个数的排列
对3个数的排列,可以转换成首位不动,完成对2个数的排列
对2个数的排列,可以转换成首位不动,完成对1个数的排列
对于1个数,无排列,直接输出结果
算法实现说明:
对n个数的排列,分成两步:
(1)首位不动,完成对n-1个数的排列,
(2)循环将后续其他数换到首位,再次进行n-1个数的排列
注:排列完成后,最终的串要与原串相同
C语言代码实现:
#include <stdio.h>
#include <string.h>
//将串左移一位,首位存到末尾。

void shift( char *s )
{
if ( !s||!s[0] ) return ; //security code . null string
char ch=s[0];
int i=0;
while( s[++i] )
s[i-1]=s[i] ;
s[i-1]=ch;
}
//本函数对于一个已排序好的数据进行全排列
void permutation(char list[], int head ) {
int i,len;
len=strlen(list) ;
if ( len-head == 1 ) //后续没有再排列的,则输出排列数据
{
printf( "%s\n", list );
}
else
{
for (i = k; i<len; i++) //从当前位置开始,每个数当一次队首,并进行后续排列
{
permutation(list, head+1); //后续串排列
shift( &list[head] ); //轮流为当第一
}
}
}
void pailie( char *str )
{
permutation( str, 0 ); //排列算法,从串的第几位开始排列
}
int main()
{
char str[]="1234";
pailie(str);
return 0;
}
带重复数据的排列问题:
如果有重复数据出现在待排列的数据中,则,若某数已经当过队首,则与其相同的数再当队首是一样的排列结果,如:1233进行全排列
当第一个3当队首时,会出现一次全排列
第二个3当队首时,会出现与第一个3当队首相同的全排列,因此,只需要保证此数据出现过队首时,不要让其再当队首就可以解决问题了。

代码实现:
//检查chk位的数据是否曾经当过队首
/*
list:待排列的全部数据
chk:待检查的位置
begin:已当过队首的数据的起始位置。

因为是移位,所以,从begin检查到list尾就可以了。

*/
is_dup( char *list, int begin, int chk )
{
int i;
for( i=begin; list[i]; i++ )
if ( list[chk] == list[i] )
return 1;
return 0;
}
void permutation(char list[], int k) {
int i,len;
len=strlen(list) ;
if ( len-k == 1 ) //后续没有再排列的,则输出排列数据
{
printf( "%s\n", list );
}
{
for (i = k; i<len; i++)
{
if ( !is_dup(list, len-(i-k), k ) ) //如果没有当过队首,则排列之permutation(list, k+1);
shift( &list[k] );
}
}
}
采用数据交换方式实现的全排列,带去重的代码:
//交换两个数的位置
void swap(char *a, char *b) {
char m;
m = *a;
*a = *b;
*b = m;
}
//检查某数据是否曾经当过队首(在已交换过的数据中进行查找)
/*
list:待排列的全部数据
end:当前交换的位置
begin:待交换的位置
*/
int is_dup( char *s, int end, int begin )
{
int i=0;
for( i=end;i>begin;i-- )
if ( s[end] == s[i-1] )
return 1;
return 0;
}
void permutation(char list[], int k) {
int i,len;
len=strlen(list) ;
if ( len-k == 1 ) //后续没有再排列的,则输出排列数据
{
printf( "%s\n", list );
}
{
for (i = k; i<len; i++)
{
if ( !is_dup ( list,i,k ) ) //如果没有重复的,则进行相应的排列,否则跳过之,因为:相同的数据当队首,交换没有意义
{
swap(&list[k], &list[i]);//交换
permutation(list, k+1); //后续串排列
swap(&list[i], &list[k]);//恢复
}
}
}
}
void pailie( char *str )
{
permutation( str, 0 ); //排列算法,从串的第几位开始排列
}
int main()
{
char str[]="1234";
pailie(str);
return 0;
}。

相关主题