递归
递归对于编程的重要性
- 递归对你的编码能力是个质的飞跃,如果你想成为一个很厉害的程序员,数据结构是必须要掌握的,计算机特别适合用递归的思想来解决问题,但是我们人类用递归的思想来考虑问题就会感到十分困扰,这也是很多学过递归的人一直都搞不明白的地方!递归的思想是软件思想的基本思想之一,在树和图论上面,几乎全是用递归来实现的,最简单,像求阶乘这种没有明确执行次数的问题,都是用递归来解决。
递归的定义
- 一个函数自己直接或间接调用自己(一个函数调用另外一个函数和他调用自己是一模一样的,都是那三步,只不过在人看来有点诡异。)
函数调用的详解
当在一个函数的运行期间调用另一个函数时,在运行被调函数之前,系统需要完成三件事:
- 将所有的实际参数,返回地址等信息传递给被调函数保存;
- 为被调函数的局部变量(也包括形参)分配存储空间;
- 将控制转移到被调函数的入口。
从被调函数返回主调函数之前,系统也要完成三件事:
- 保存被调函数的返回结果;
- 释放被调函数所占的存储空间;
- 依照被调函数保存的返回地址将控制转移到调用函数。
当有多个函数互相调用时,按照“”后调用先返回“”的原则,上述函数之间信息传递和控制转移必须借助“”栈“”来实现,即系统将整个程序运行时所需的数据空间安排在一个栈中,每当调用一个函数时,就在栈顶分配一个存储区,进行压栈操作,每当一个函数退出时,就释放它的存储区,进行出栈操作,当前运行的函数永远都在栈顶位置。
A函数调用A函数和A函数调用B函数在计算机看来是没有任何区别的,只不过用我们日常的思维方式理解比较怪异而已!
递归满足的三个条件
- 递归必须得有一个明确的终止条件
- 该函数处理的数据规模必须在递减
- 这个转化必须是可解的
循环和递归的比较
递归:
- 容易理解
- 速度慢
- 存储空间大
循环:
- 不容易理解
- 速度快
- 存储空间少
理论上循环能解决的,肯定可以转化为递归,但是这个过程是复杂的数学转化过程,递归能解决不一定能转化为循环,有没有能力运用看个人。
用递归解决汉诺塔问题
伪算法:
if(n > 1)
{
//先把A柱子上的前n-1个盘子从A借助C移动B
//将A柱子上的第n个盘子直接移到C
//再讲B柱子上的n-1个盘子借助A移到C
}
具体实现:
#include <stdio.h>
#include <stdlib.h>
void hannuota(int n,char A,char B,char C)
{
/*如果是一个盘子,直接从A柱子上的盘子从A移到C
否则,将A柱子上的n-1个盘子借助C移到B.直接将A柱子上的盘子从A移到C,
最后将B柱子上的n-1个盘子借助A移到C*/
if(1 == n)
printf("将编号为%d的盘子直接从%c柱子移到%c柱子\n",n,A,C);
else
{
hannuota(n-1,A,C,B);
printf("将编号为%d的盘子直接从%c柱子移到%c柱子\n",n,A,C);
hannuota(n-1,B,A,C);
}
}
int main()
{
char ch1 = 'A';
char ch2 = 'B';
char ch3 = 'C';
int n;
printf("请输入盘子的个数:");
scanf("%d",&n);
hannuota(n,'A','B','C');
return 0;
}