版权声明:本文为博主原创文章,若有错误之处望大家批评指正!转载需附上原文链接,谢谢! https://blog.csdn.net/summer_dew/article/details/83111688
组合
【问题】从长度为n个字符串str中选出m个元素的可能
【思路】
【代码】
char *tmp; //中间结果
int top;
int count; //种数
//递归求组合数
void combination(char *str, int n, int m )
{
if( n < m || m == 0 ) return ; //case 1:不符合条件,返回
combination( str+1, n-1, m ); //case 2:不包含当前元素的所有的组合
tmp[ top++ ] = str[0]; //case 3:包含当前元素
if( m == 1 ){ //case 3.1:截止到当前元素
printA( tmp, top );
printf("\n");
count++;
top--;
return;
}
combination( str+1, n-1, m-1); //case 3.2:包含当前元素但尚未截止
top--; //返回前恢复top值
}
【理解】将递归树进行先序输出
树状的方式类似于这种https://blog.csdn.net/summer_dew/article/details/82937941
【完整代码】
#include<stdio.h>
#include<stdlib.h>
char *tmp; //中间结果
int top; //
int count; //种数
//打印长度为n的数组元素
void printA(char *str,int n)
{
int i;
for(i=0;i<n;i++){
printf("%c ",str[i]);
}
}
//递归求组合数
void combination(char *str, int n, int m )
{
if( n < m || m == 0 ) return ; //case 1:不符合条件,返回
combination( str+1, n-1, m ); //case 2:不包含当前元素的所有的组合
tmp[ top++ ] = str[0]; //case 3:包含当前元素
if( m == 1 ){ //case 3.1:截止到当前元素
printA( tmp, top );
printf("\n");
count++;
top--;
return;
}
combination( str+1, n-1, m-1); //case 3.2:包含当前元素但尚未截止
top--; //返回前恢复top值
}
int main()
{
int n,m;//存放数据的数组,及n和m
char *str;
printf("输入n与m,用空格隔开\n>>> ");
scanf("%d%d",&n,&m);
str = (char *) malloc( sizeof(char) * n );
tmp = (char *) malloc( sizeof(char) * m );
printf("输入字符串\n>>> ");
scanf("%s", str);
printf("\n%s %d中选取%d个", str, n, m);
combination( str, n, m );//求数组中所有数的组合
printf("总数%d\n", count);
return 0;
}
错误思路
【举例】字符串’ABCD’,即4个元素中选3个出来
【思路】
有A的情况
1. ABCD固定不动,取前三个位置--> ABC
2. ABCD--> 将B、D互换--> ADCB--> 取前三个位置--> ADC
3. ABCD--> 将C、D互换--> ABDC--> 取前三个位置--> ABD
没有A的情况:等同于,在字符串'BCD'中任选3个 => 回到了初始的问题
1. BCD固定不动,取前三个位置--> BCD
2. 没有其他元素了,就不必下去了
【转换成代码】
- 前面的思路其实是把字符串划分成了两个部分
- “ABC”:当前序列
- “D”:备选序列
- 实际就是把 ‘BC’ 中的每个元素,与’D’的每个元素,逐一交换后输出
- “BC”:当前序列(“ABC”)中除去第一个元素’A’的序列
- “D”:备选序列
【代码】
// 组合
void combination(char* str, int sbegin, int send)
{
int i,j,z;
// send没有超出元素的界限
if ( send < n )
{
// -- 有str[sbegin]的时候
// 原序列输出
for ( z=0; z<m; z++ )
{
printf("%c", str[z+sbegin]);
cnt++;
}
printf("\n");
// 与备选的元素交换,找出其他可能
for ( i=sbegin+1; i<=send; i++ ) { //目前序列除第一位的其他元素
for ( j=send+1; j<n; j++ ) { //与备选序列中的每个元素
swap(&str[i], &str[j]); //交换
// 输出
for ( z=0; z<m; z++ ) {
printf("%c", str[z+sbegin]);
cnt++;
}
printf("\n");
swap(&str[i], &str[j]); //注意换回来
}
}
// -- 没有str[sbegin]的时候
combination(str, sbegin+1, send+1);
}
}
【错误所在】
少了一种情况"ADE",–>"ABC"中"BC"和候选元素"DE"一起换的时候没有考虑到–> 里面不应该是简简单单的输出,也是一种递归