递归算法的定义:程序直接或间接调用自身的编程技巧称为递归算法(Recursion)。
递归的说明:一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法.它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
我们为什么要使用递归算法?
首先应当指出的是递归程序比较简洁,只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
我们在处理一些问题时,会发现一个大问题实际上是有一些小问题组成,而这些小问题又是容易解决的。我们一般会想到使用递归算法来解决此类问题。
递归算法的基本套路:
首先:它有一个基本部分,即直接满足条件,输出或返回,这也就是递归的边界条件,即满足条件则找到递归出口,不满足则接着递归。
其次:他必须有一个递归函数,通过改变递归函数的参数来依次递归
最重要的是递归函数在实现的过程中,它采用了分治法的思想:
即将整体分割成部分,并总是从最小的部分(基本部分)开始入手(输出),其背后的原理在于 当整体递归到部分时,会保留整体的信息,部分满足条件输出的结果会被回溯给整体使用,从而使得整体输出结果。
递归函数也并非十全十美的:
递归算法的实现效率是比较低下的。递归效率低是函数调用的开销导致的。
在一个函数调用之前需要做许多工作,比如准备函数内局部变量使用的空间、搞定函数的参数等等,这些事情每次调用函数都需要做,因此会产生额外开销导致递归效率偏低,所以逻辑上开销一致时递归的额外开销会多一些。
另外递归函数在调用过程中,系统为每一层的返回点、局部变量等开辟了堆栈来存储。递归次数过多容易造成堆栈溢出等。
例:Fibonacci数列的递归算法
int fib (int n)
{
if(n<=1) return 1;
return fib(n-1)+fib(n-2);
}
这是一个很简单也很经典的递归函数,但是这个函数有一个问题,由于函数重复递归的次数太多导致该递归函数的效率比较低。
当然啦,递归函数在解决二叉树方面有着独特的优势:
例如:二叉树的前序遍历
void qianxu(TreeNode * root)
{
if(root==NULL)return;
cout<<root->data<<endl;
qianxu(root->left);
qianxu(root->right);
}
例:汉诺塔问题:
问题描述:
有n个盘子, 从小到大 依此从上往下叠放,在1号位。 1号位,2号位,3号位从左到右相邻。
现需要将n个盘子,从1号位通过2号位移到3号位,或者从3号位置通过2号移到1号。 移动的过程中,不允许,大盘叠在小盘上。
//n 为 盘子的数目
//a 为1号位, b 为2号位, c为3号位
void hanoi(int n, char a, char b, char c)
{
if (n == 1) // 输出条件
{
std::cout << a << b << c << std::endl; //特点1,基本部分
}
else{ // 特点2 递归部分
//特点4: 以下为 整体利用部分为其一步,完成当前整体整个步骤
hanoi(n - 1, a, b, c); //特点3 整体化为部分,部分视为1步,即将n-1个盘子 从a 移到c
std::cout << a << b << std::endl; // 第n个盘子从 a 到 b
hanoi(n - 1, c, b, a); // 特点3
std::cout << b << c << std::endl;
hanoi(n - 1, a, b, c); //特点3
}
}