一.分组问题
题目:用递归法计算从n个人中选选k个人组成一个委员会的不同组合数。
分析:由n个人里选k个人的组合数 = 由n-1个人里选k个人的组合数 + 由n-1个人里选k-1个人的组合数;当n = k或k = 0时,组合数为1。
<!--more-->
#include <iostream>
using namespace std;
/*双递归的执行过程,可以借助二叉树结构来描述*/
int comm(int n, int k) {//排除n < k的情况
if (n < k) {
return 0;
}
else if(n == k || k == 0)//递归函数的出口
{
return 1;
}
else {//两个递归深入点,但是同函数中左右深入点的深入层次并不一定相同
return comm(n - 1, k) + comm(n -1, k - 1);
}
}
int main() {
int n, k;
cin >> n >> k;
cout << comm(n, k);
system("pause");
return 0;
}
二.双递归函数的执行顺序
双递归的执行过程,可以借助二叉树结构来描述:
- 程序从首先左端的递归深入点进入,再次调用函数(4, 3),再次从左侧深入点(3, 3)深入。此时得到第一个递归的终止条件:n = k,组合数为1,将1返回给父级节点;在此之前,(4, 3)右端的函数深入点并未执行,而是作为没有执行完毕的函数被保存在栈中。此时则是执行(4, 3)右侧递归深入点(3, 2)函数。剩余执行过程由红色箭头标识,不再一一说明。
- 无论执行左侧还是右侧函数,调用时必定先执行左子树所代表的函数。若此时这棵左子树依然存在后代,则先执行它的左子树函数,然后循环此逻辑;直到左子树没有下级节点时,那么就返回它的上级节点,来执行上级节点的右子树函数。
- 使用二叉树表示的双递归函数执行过程中,任何一个节点若存在子节点,那么它的左后代与右后代必然是同时存在的。原因就在于在递归调用函数时,两个调用自身的函数也是同时存在的。
- 当一个节点找到递归出口时,那么与它有相同父级节点的兄弟节点不会停止递归深入,直到得到一个可以返回的值为止(即找到递归出口)。所以,叶子结点返回值逐级累加,所有的返回值之和,就是题目所求结果,也就是整个递归最外层函数的返回值即函数调用者(此题为main函数)所需要的结果。
- 可以使用断点调试对变量进行监视,从而更好地理解双深入点递归函数的执行过程。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。