函数的递归是在某个函数里(非主函数)自己调用自己,很显然必须在某条件下可以终止对自己的调用。
函数的重载是针对同名函数进行动态匹配,针对不同特点匹配特定函数实现。
递归
递归应该是算法设计的入门,现实生活中很多问题用递归的思想可以得到很好的解决。然而递归不是一种高效的算法。
函数的调用流程是这样的:主调函数发起函数调用-》主调函数暂停,保存现场-》进入被调函数-》被调函数执行完毕,恢复主调函数现场,主调函数继续执行。
递归调用需要不断地保存、恢复现场,效率并不高,但是很多问题都可以通过递归的思想来完成:
1、阶乘和斐波拉契:既可以递推,也可以递归;
1! -> 2! -> 3!.... 递推
n! -> n*(n-1)! -> n*(n-1)*(n-2)! ..... ->n*(n-1)*(n-2).....1! 求n的阶乘转成求n-1,一直到已知的1的阶乘,然后再一层层返回。
斐波拉契级数也一样。
#include <iostream>
#include <stdio.h>
using namespace std;
int f1(int n) //递归求阶乘
{
if(n==1 || n==0) return 1;
return n*f1(n-1);
}
int f2(int n) //递归求斐波拉契
{
if(n==1 || n==2) return 1;
return f2(n-1)+f2(n-2);
}
int main()
{
cout<<f1(5)<<endl;
cout<<f2(8)<<endl;
return 0;
}
上面代码可以发现递归算法从代码方面而言非常的简练、求解的思想也非常清晰!
2、经典汉诺塔问题
A、B、C三个柱子,在A柱子从小到大叠有N个盘子,目标是把A柱子上的盘中移动到C柱子上,移动规则是不能用大盘中压住小盘中。
#include <iostream>
#include <stdio.h>
using namespace std;
void hanoi(int n,char A,char B,char C)//n个盘在A,要移动到C
{
if(n==1) cout<<"第"<<n<<"号盘从 "<<A<<" 移动到 "<<C<<endl; //一个盘在A,直接移动到C
else
{
hanoi(n-1,A,C,B);//多于一个盘,则把n-1个盘移动到B
cout<<"第"<<n<<"号盘从 "<<A<<" 移动到 "<<C<<endl; //剩余的盘移动到C
hanoi(n-1,B,A,C); //再把B上的n-1个盘,移动到A
}
}
int main()
{
hanoi(4,'A','B','C');
return 0;
}
以上代码就非常让人惊讶了,如果用普通的逻辑推理,估计很难解决问题,这就是递归的优雅!
递归的特点:
1、递归是重复调用自己,每次调用肯定需要有些变化,其中变化的称为递归元;递归元可以是多个,称为多元递归;
2、递归可以直接自己调用自己,也可以间接调用,如A调用B,B又调用了A,称为间接递归;
3、递归需要有一个终止条件(不需要递归调用),并且递归元必须朝这个终止条件发展,否则将进入死循环
4、递归算法很优雅,但效率不高,递归算法的非递归化是算法研究的难点;
5、递归天然与”栈“这种数据结构相似,栈是一种线性结构(一维,有前后次序),满足后入先出的规则(类似穿衣服,最后穿的衣服先脱掉)。所以,很多时候可以用栈来描述递归算法(STL里)。
函数重载
函数是重名(相同函数名)调用时自动匹配函数定义,或者说同一个函数调用根据不同的条件调用不同的函数。规则:
重载的函数形参要么个数不同,要么类型不同(避免歧义)
void f1(int x)
{
}
void f1(int x,int y) //形参个数不同
{
}
void f1(float x,float y) //形参类型不同
{
}
void f1(int x,double y=10) //错误,与第一个定义冲突
{
}
int f1(int x) //错误,函数类型(返回值)不能做为重载依据
{
return 0;
}
调用时,通过实参找到最匹配(有可能都不匹配,但有一个最符合),如果有歧义也会报错:
f1(1.5,6); 1.5是double ,从第二、第三个都无法匹配,歧义 错误
f1(5,6.1); 5是int 6.1是double ,从第二比第三个更接近 调用第二个
f1(5.0f,6.1); 5.0f是float 6.1是double ,从第三比第二个更接近 调用第三个
f1(5.0,6.0); 两个double , 二、三都不匹配,歧义,错误
f1(5.0,6); 5.0是double , 6是int 第二比较匹配,调用第二个
结论:在参数个数相同下,匹配规则就是计算相同的(不需要赋值转换的),如果两个函数相同个数一样就会歧义。