一 概念解释
递归(recursive)定义为一种直接或间接引用自身的定义方法,通俗的说,即是:自己调用自己的函数(或称为方法)。
二 递归算法结构
一个合法的递归包括两个部分:基础情况和递归部分。基础情况以直接形式明确列举新事物的若干简单对象,递归部分给出由简单(或较简单)对象定义新的条件和方法。
三 算法思想内核
在程序设计中,处理重复性计算最常用的方法是组织迭代循环,此外还可以采用递归计算的方法,后者在非数值计算领域适用性更强。递归本质也是一种循环,将较复杂的计算或问题不断分解为较简单的子部分,最后得出结果。例如,递归算法典例:斐波那契数列的求解:
斐波那契级数的递归定义:
F(0)=0;
F(1)=1;
F(n)=F(n -1)+F(n-2) (n>1)
可写出函数:
long Fib(int n)
{
if(n==0||n==1)
return n;
else
return Fib(n-1)+Fib(n-2);
}
函数P()调用函数Q(),P称为调用函数,Q称为被调函数。当被调函数为P本身时,称其为递归函数,如Fib(n)。
四 递归算法应用
1 逆序输出正整数的各位数
——设有正整数n=123456,现要求逆序输出654321,设k位正整数为d1d2d3……dk,要输出逆序的dkdk-1……d2d1。
若采用for循环的方式分离出正整数的每一位数字:
#include<stdio.h>
#include<math.h>
void getNum(int n)
{
int s;
int len=(int)log10(n)+1; //获得n的位数
for(int i=0;i<len;i++)
{
s=n%10;
printf("%d ",s);
n=n/10; //更新n的取值
}
}
int main()
{
int n;
scanf("%d",&n);
getNum(n);
return 0;
}
若采用递归方法则分为两步:首先输出末位数dk——然后输出前k-1位组成的正整数的逆序形式。
#include<iostream.h>
void Print(int n)
{
count<<n%10;
if(n>=10)
Print(n/10);
}
void main()
{
unsigned int n;
cin>>n;
Print(n);
}
2 汉诺塔问题
——有三个塔座:x,y,z,在塔座x上有n个直径大小各不相同的的圆盘,按直径大小从小到大编号为1,2,3……n。现要求将x塔座上的n个圆盘移到塔座y上,且仍按照相同顺序排列,即如图。圆盘移动时必须遵守下列规则:
1 每次只能移动一个圆盘;
2 圆盘可以加到塔座x,y,z中任意一个之上;
3 任何时刻都不能将一个较大的圆盘放在一个较小的圆盘之上。
假定圆盘从小到大编号为1~n,移动圆盘的递归算法可以粗略描述如下:
1 以塔座y为中介,将前n-1个圆盘从塔座x移到塔座z上;
2 将第n个圆盘移到塔座y上;
3 以塔座x为中介,将塔座z上的n-1个圆盘移到塔座y上。
汉诺塔问题:
#include<iostream.h>
enum tower{A='X',B='Y',C='Z'};
void Move(int n,tower x,tower y)
{
cout<<"The disk"<<n<<"is moved from"<<char(x)<<"to top of tower" <<char(y)<<endl;
}
void Hanoi(int n,tower x,tower,y,tower z)
{
if(n){
Hanoi(n-1,x,z,y);
Move(n,x,y);
Hanoi(n-1,z,y,x);
}
}void main()
{
Hanoi(4,A,B,C);
}
单向链表转置、八皇后问题、全排列等(待完成)
五 递归树
递归树是设计好的猜测一种简单而直接的办法。顾名思义,递归树具有树的结构,其中每个节点表示一个单一子问题的代价,子问题对应某次递归函数调用,将树中每层中的代价求和,得到每层代价,然后将所有层的代价求和,便可得到所有层次的递归调用的总代价。
对于上述的斐波那契级数求解的问题(以fib(4)的构成为例):
由图可知,在执行Fib(4)的过程中,须分别调用Fib(3)和Fib(2),而Fib(2)又分别调用Fib(1)和Fib(0)……整个过程中,Fib(0)调用了两次,Fib(1)调用了三次,Fib(2)调用了两次,并可以推想,在数据规模不断扩大的过程中,重复计算的次数也会不断提升,在此过程中浪费的时间也会愈多。
六 递归优缺点梳理
优点:程序设计简洁清晰、易于分析。
缺点:运行过程中的嵌套调用特性导致其时空效率往往相对较低。
七 递归的实现原理(待补充)
八 递归思想的应用
1 数据结构中,树、二叉树和列表常采用递归方式来定义,包括其相关操作(如二叉树树的遍历、二叉树树的元素的增删改查等)也常利用递归的方法。
2 后面即将提到的算法设计方法——分治法,也是递归思想的重要应用。