一.分组问题

题目:用递归法计算从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;
}

 

 

二.双递归函数的执行顺序

双递归的执行过程,可以借助二叉树结构来描述:

二叉树描述双递归执行过程

  1. 程序从首先左端的递归深入点进入,再次调用函数(4, 3),再次从左侧深入点(3, 3)深入。此时得到第一个递归的终止条件:n = k,组合数为1,将1返回给父级节点;在此之前,(4, 3)右端的函数深入点并未执行,而是作为没有执行完毕的函数被保存在栈中。此时则是执行(4, 3)右侧递归深入点(3, 2)函数。剩余执行过程由红色箭头标识,不再一一说明。
  2. 无论执行左侧还是右侧函数,调用时必定先执行左子树所代表的函数。若此时这棵左子树依然存在后代,则先执行它的左子树函数,然后循环此逻辑;直到左子树没有下级节点时,那么就返回它的上级节点,来执行上级节点的右子树函数。
  3. 使用二叉树表示的双递归函数执行过程中,任何一个节点若存在子节点,那么它的左后代与右后代必然是同时存在的。原因就在于在递归调用函数时,两个调用自身的函数也是同时存在的。
  4. 当一个节点找到递归出口时,那么与它有相同父级节点的兄弟节点不会停止递归深入,直到得到一个可以返回的值为止(即找到递归出口)。所以,叶子结点返回值逐级累加,所有的返回值之和,就是题目所求结果,也就是整个递归最外层函数的返回值即函数调用者(此题为main函数)所需要的结果。
  5. 可以使用断点调试对变量进行监视,从而更好地理解双深入点递归函数的执行过程。
     

 

 



Solryu
18 声望6 粉丝