【C++学习】函数(二)——递归调用(详解汉诺塔问题)

概念:

函数可以直接或间接地调用自身,称为递归调用。

所谓直接调用自身,就是指在一个函数的函数体中,出现了对自身的调用表达式。

直接调用自身:

void fun1()
{
 fun1(); //调用fun1自身
}

间接调用自身:

void fun1()
{
 fun2();
}
void fun2()
{
 fun1();
}

递归的过程有如下两个阶段:
第一阶段:递推。将原问题不断分解为新的子问题,逐渐从未知向已知推进表,最终达到已知的条件,即递归结束的条件,这时递推阶段结束。

第二阶段:回归。从已知条件出发,按照地推的逆过程,逐一求值回归,最后达到递推的开始处,结束回归阶段,完成递归调用。

汉诺塔问题:

有三根针A,B,C,A针上有n个盘子,盘子大小不等,大的在下,小的在上,如图所示。要求把这n个盘子从A针移到C针,在移动过程中可以借助B针,每次只允许移动一个盘,且在移动过程中在三根针上都保持大盘在下,小盘在上。

 一、分析

当n=3时,需要把A上的盘子借助B移到C上。

如果最大的盘子需要移到C,则意味着其他所有盘子按顺序从小到大依次叠放B上,因此,可以得到最后一层示意图如下:

 此时,我们需要把A上剩下的一个盘子移到C上,再将B上的两个盘子移到C上。A—>C显而易见,因此现在把问题聚焦到B上的两个盘子。现在的问题相当于把B上的两个盘子借助A移到C上。这是一个和原问题类似的子问题,它的解决方法和上面的思路类似,即进入递归的过程。因此,汉诺塔问题可以分为以下3个步骤:

  1. 将A上n-1个盘子移到B针上(借助C针)。
  2. 把A针上剩下的一个盘子移到C针上。
  3. 将n-1个盘子从B针移到C针上(借助A针)。

事实上,上面三个步骤包含下面两种操作:

  1. 将多个盘子从一个针移到另一个针上,这是一个递归的过程。
  2. 将1个盘子从一个针上移到另一个针上。

结合上述分析,“把A上的3个盘子借助B移到C上”"把B上的2个盘子借助A移到C上"属于(1);"A—>C"属于(2)。

二、代码

2.1 构造函数

用hanoi函数实现第一种操作(递归),用move函数实现第二种操作。

//n层汉诺塔
//if n==0 时,递归过程结束
//一个起始柱,一个中间柱,一个目标柱


void move(char start, char destination)
{
    cout << start << "--->" << destination<<endl;
}

//将n个盘子从A通过B移到C
void hanoi(int n, char start, char medium, char destination)
{
    if (n == 0)
        return;
    else
    {
        //将n-1个盘子从A通过C移到B
        hanoi(n - 1, start, destination, medium);
        //将剩下一个盘子从A移到C
        //输出操作
        move(start, destination);
        //将n-1个盘子从B通过A移到C
        hanoi(n - 1, medium, start, destination);
    }
}

主函数:

int main()
{
    int n;
    cout << "Enter the number of diskes:";
    cin >>n;
    hanoi(n, 'A', 'B', 'C');
    return 0;
}

运行结果:

 三、递归过程

总结与反思:

 递归问题解决的关键在于分解找出子问题,而不在于在脑子里模拟出每一步是如何运行的,尤其面对更复杂的问题时,要靠人脑解决全过程是十分困难的。递归的过程其实就是不断调用函数的过程,在这方面,程序的运行思路是严格依照代码运行顺序执行的,和人脑的思路不太一样,所以递归问题千万不能复杂化,不需要执意弄清楚每一步是如何产生的,而是要找准递归的子问题,分析递归过程。

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值