简书内代码已上传GitHub:点击我 去GitHub查看代码
这里用到的顺序栈代码可以点击 : 顺序栈 查看
一.组合问题
早上看见学校老师发的PPT最后留了道题:
组合问题
...然后就想到了之前做过的一个问题:
求一个集合子集和为定值的所有子集,有兴趣可以做做
组合问题相对来说简单很多,就是对递归进行简单运用
二.思路:
提到组合这两个字,大家小时候学数学应该老师都教过从几个数字中找出不重复的2个数字怎么找:
连线法
首先我们做一个规定:从左往右选择组合。元素连线的左端是第一个选择的元素, 右端是第二个选择的元素。
因为在4 个 中选 2 个,且有以上规定(从左往右选),所以第一个元素的范围是:1、2、3 , 因为要给第二个元素留下一个选择项4.第二个元素的范围就是所选的第一个元素的右侧的所有元素。
我们可以把以上规则归纳以下,扩展到n个元素取m个的组合。选取元素的范围应该是:index + 1 ~ n - rest , rest是组合中剩余的应选元素。
三.递归实现:
在这里存储组合所用的数据结构选择了栈。
int a[] 存储待组合元素, start是第一次选择的元素, n是元素总数, m是选取的个数。
//求a数组元素所有组合
void combine(SqStack &s, int a[], int start, int n, int m){
int e; //无用
//循环取出元素(广度上的搜索),需要搜索 start ~ n - m
for(int i = start; i <= n - m; ++i){
//把第一个元素入栈
Push(s, a[i]);
//如果需要组合需要的元素 > 1 , 递归深度 + 1 ,继续取出元素
if (m > 1)
combine(s, a, i + 1, n, m - 1);
//如果在这个深度已经取完所有的元素,遍历栈,输出
else{
StackTraverse(s, print);
printf("\n");
//弹出栈顶,在当前深度继续搜索
Pop(s, e);
}
}
//弹出栈顶元素(上一深度所选元素),返回上一深度,继续广度上的搜索
Pop(s, e);
return;
}
四.测试:
集合{1,2,3,4,5}中选3个数的所有组合:
测试
脑子太久不用就会生锈啦,一想递归的逻辑就晕...
每天进步一点,加油!
End
END