递归函数
一个自定义的函数可以被main函数和其它函数调用,如果自定义函数在函数体内调用它自身,我们就称为递归函数(recursion)。
例1:输入一个数n,求n+(n-1)+(n-2)…..1的和?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include<iostream> using namespace std; int f(int a){ if(a==1)return 1; else return a+f(a-1); } int main(){ int n; cout<<"please input a number:"; cin>>n; cout<<f(n); } |
递归调用的终止条件
每一个递归函数都应该只进行有限次的递归调用,否则它就会进入死胡同,永远也不能退出了,这样的程序是没有意义的。
要想让递归函数逐层进入再逐层退出,需要解决两个方面的问题:
1、存在终止条件,当符合这个条件时递归便不再继续。
2、每次递归调用之后越来越接近这个终止条件。
递归函数的几种形式
1、尾递归,也就是递归调用位于函数体的结尾处 ;
2、中间递归:发生递归调用的位置在函数体的中间;
3、多层递归:在一个函数里面多次调用自己。
递归函数的优缺点
优点
- 代码简洁明了:递归函数通常比等效的非递归实现更加简洁,更易于理解和维护,尤其是在处理复杂问题时。
- 问题分解:递归提供了一种自然的方法来分解问题,将复杂问题分解为更小、更易于管理的子问题。
- 适合解决某些类型的问题:对于像树遍历、图搜索等自然具有递归结构的问题,递归方法特别有效和直观。
- 减少代码量:在某些情况下,使用递归可以减少代码量,使代码更加紧凑。
缺点
- 性能问题:递归函数可能会导致额外的函数调用开销,尤其是在深度递归的情况下。每次函数调用都会消耗栈空间,导致性能下降。
- 栈溢出的风险:深度递归可能导致调用栈过大,从而引发栈溢出错误。这是因为每个函数调用都会在栈上占用一定的空间,而栈的大小是有限的。
- 调试困难:递归逻辑有时可能难以理解和跟踪,特别是对于复杂的递归函数,这可能使得调试变得更加困难。
- 非最优性能解:对于某些问题,递归解决方案可能不是最高效的。例如,使用循环代替递归可以避免函数调用的开销,从而提高性能。
所有递归都可以用循环实现
Quizzes
