《数据结构》第五章:递归

5.1 递归基础

函数直接或间接地调用自身,称为递归调用。含有递归调用地函数称为递归函数。递归调用用的是相同地策略去解决规模更小的问题,直至问题规模小于或等于某个边界条件时,不再进行递归调用,而是直接处理。

5.1.1汉诺塔问题

有3根柱子A、B、C,啊hi有一组数量为n、大小不一的圆盘。开始时,所有圆盘从大到小叠放在A柱上。游戏任务是将所有圆盘从A移动的任何时刻都不允许大盘子在小盘子之上,每次移动只能移动最上面的一个盘子

现从1开始对圆盘从小到大编号。圆盘数量决定了汉诺塔问题的复杂程度。

当n=1时,可直接将盘子从A移动到C。

当n=2时,由于规则限制,既不能将两个盘子立即从A移动到C,也不能直接把2号盘抽出来移动到C,所以为了移动2号盘,唯有先把1

号盘从A移动到B,然后将2号盘从A移到C,最后将1号盘B移到C。

当n=3时,仍然可以沿用n=2时的思路,为了移动3号盘,先将1号盘和2号盘从A移动到B,剩余步骤也类似。

由上述分析可以得到n>1时的一般求解步骤。

  1. 将1至n-1号盘从A柱移动到B柱。
  2. 然后将n号盘从A柱移动带C柱。
  3. 将1至n-1号盘从B移动到C柱。

其中步骤(1)和(3)是求解n-1规模的汉诺塔问题,可用递归调用实现。

算法:汉诺塔

void hanoi(int n,char x,char y,char z){

    //以y为中转柱,将n个盘从x移动到目标柱z

    if(n==1)

    {
    
    move(x,1,z);//将1号盘从x移动到z柱

    }

    else{

    hanoi(n-1,x,z,y)//将1至n-1号盘从x柱移动到y柱,z为中转柱

    move(x,n,z);//将n号盘从x柱移动到z柱

    hanoi(n-1,y,x,z);//将1至n-1号盘从y柱移动到z柱,x为中转柱

    }

}

5.1.2递归函数执行过程

在程序执行过程中,递归函数调用与一般函数调用的处理相同。但在递归函数执行过程中,每次递归调用时,总会跳转至函数的入口处执行,造成重新执行的假象。实际上在递归调用中,虽然代码被重复执行,但每次执行时程序的运行空间(包括局部变量、传递参数和返回结果)并不相同,所以两次递归调用的执行过程其实是完全不同的。

函数递归调用的嵌套层数称为递归层次。其他函数对递归函数的调用称为第0层调用。

函数调用时的执行过程可以借助函数调用栈来完成。但函数M调用函数F时,暂停执行M,转去执行F。当F执行结束,则返回M继续执行,继续执行的指令地址称为返回地址RA。每次发生函数调用时,在栈顶开辟一段称之为栈帧的存储空间,用于存放实参、局部变量和返回地址等。

在执行F的代码之前,系统需要完成以下工作:

  1. 将所有实参、返回地址等信息传给F。
  2. 为F中的局部变量分配存储空间。
  3. 转到F的第一条将要被执行的代码(入口代码)处,准备开始执行。

当F的代码执行完毕,在返回M之前,系统需要进行以下工作。

  1. 保存F的计算结果(如果有)。
  2. 释放F使用的栈帧,包括实参和局部变量占用的空间等。
  3. 转到返回地址RA,继续执行。

如果函数M对自身递归调用,相当于函数M与F是同一个函数。假设主函数main在第i行调用了汉诺塔函数hanoi(3,A,B,C):

void main(){

...

hanoi(3,A,B,C);//第i行

...

}

调用hanoi(3,A,B,C)时,在函数调用栈中压入栈帧“i+1,3,A,B,C”,其中i+1是返回地址,3,A,B,C是传递的实参。当hanoi(3,A,B,C)执行到第4行时,进入第1层递归调用hanoi(2,A,B,C),此时压入栈帧“5,2,A,C,B”,返回地址为5.同理hanoi(2,A,C,B)执行至第4行时发生第2层调用hanoi(1,A,B,C),并压入栈帧“5,1,A,B,C”。

当hanoi(1,A,B,C)执行完毕,则栈帧“5,1,A,B,C”出栈,返回执行第1层hanoi(2,A,C,B)的第5行继续执行,到第6行时又发生第二层调用hanoi(1,C,A,B),压入的栈帧为“7,1,C,A,B”。这两次进入第二层的返回地址和实参都不同,是两次不同的函数调用。

5.2 递归与分治

分治是指将一个难以直接解决的大问题,递归分割成一些规模较小的相同问题,以便逐个解决。

5.2.1 分治法

具有以下特征问题可用分治法求解。

  1. 当问题规模小到一定程度,可以直接求解。
  2. 当问题规模较大时,可以分解为若干个相互独立的子问题,这些子问题与原问题具有相同的特征。若不能直接求解,则可分为递归求解。
  3. 原问题的解时子问题解的组合,其组合方法根据问题的具体情况而定。

分治法的基本思路是,把规模为n的输入分割成k(2≤k≤n)个子集,从而产生l个子问题(一般情况下l≥k),分别求解得到l个子问题的解,并将子解组合成原问题的解。

例如:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sɪʟᴇɴᴛ໊ོ5329

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值