递归——从汉诺塔问题谈起

引子

古代有一个梵塔,塔内有三个座A、B、C,A座上有64个盘子,盘子大小
不等,大的在下,小的在上。有一个和尚想把这64个盘子从A座移到C座,但每次只能允许移动一个盘子,并且在移动过程中,3个座上的盘子始终保持大盘在下,小盘在上。在移动过程中可以利用B座,要求输出移动的步骤。

动画示例

将盘子从A座移动到C座,由于从A移出是按照从小到大的顺序移出的,移动到C时是按照先放大的后放小的的顺序排列,所以要借助B座中转。以3个盘子为例:

  1. A->C
  2. A->B
  3. C->B
  4. A->C
  5. B->A
  6. B->C
  7. A->C

除了第4步,前三步和最后三步的实现步骤一致,都是将2个盘子移动到另一根柱子上,第四步是将A座最大的盘子移动到C座。由于题目规定必须大盘在下小盘在上,所以要保证A座只剩一个最大的盘子,C座不能有盘子,B座有2个盘子。将最大的盘子从A移动到C之后剩下的步骤和将2个盘子从A移动到B方法相同。
我们将问题推广到n个盘子的汉诺塔问题,将n个盘子的移动问题化简为n-1个盘子的移动问题,然后再将n-1个盘子的移动问题化简为n-2个盘子移动问题……这就是递归的思想。

递归定义

函数定义中使用函数自身的方法

经典的递归例子:求阶乘

n!=(n1)(n2)(n3)(n4)...(1)

举例:5!=5(4)(3)(2)(1) =5 * 4!
推广: n!=n(n-1)!
阶乘的递归定义:
阶乘递归定义
0的阶乘:定义为1
其他数字:定义为这个数字乘以比这个数字小1的数的阶乘
最后计算基例:0!。0!是已知值。
递归定义特征 :

  1. 有一个或多个基例是不需要再次递归的。
  2. 所有的递归链都要以一个基例结尾。

阶乘的递归定义函数 :

int Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n - 1);
}

递归求阶乘运行图示:

这里写图片描述

递归的栈内存图示:

这里写图片描述

汉诺塔问题代码实现

这里写图片描述

#include <iostream>
using namespace std;
void Hanoi(int n, char src,char mid,char dest)
//将src座上的n个盘子,以mid座为中转,移动到dest座
{
    if( n == 1) { //只需移动一个盘子
    cout << src << "->" << dest << endl;
    //直接将盘子从src移动到dest即可
    return ; //递归终止
    }
    Hanoi(n-1,src,dest,mid); //先将n-1个盘子从src移动到mid
    cout << src << "->" << dest << endl;
    //再将一个盘子从src移动到dest
    Hanoi(n-1,mid,src,dest); //最后将n-1个盘子从mid移动到dest
    return ;
}
int main()
{
    int n;
    cin >> n; //输入盘子数目
    Hanoi(n,'A','B','C');
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值