递归:递归是通过调用自身的一个副本一步一步求解小问题从而解决大问题的一种方法
一般我们写递归的基本流程:
if(是结束条件吗) 直接求解并返回结果 else if(是另一种结束条件吗) 直接求解并返回结果 else return(进行某些需要的操作并调用本身)
来个例子更好的理解一下,以逆序的方式输出3到1:
int Print(int n){ if(n ==1){ cout<<"1"<<endl; return 0; } else{ cout<<n<<endl; Print(n-1); }
}
当我们写一个程序的时候,我们不单单只关注我们是否达到目的,还要思考这个程序带来的开销是否是我们所能承受或者合理的
递归函数之所以称之为递归是因为每次都要调用其本身,那么每次调用递归函数的时候,都会在内存中产生递归函数的副本,实际上是函数中的变量副本,一旦一次递归完成了,那么对应副本也将删除,拿上例来说:
Print(3)调用Print(2),Print(2)调用Print(1),Print(1)返回 0 给Print(2),Print(2)返回0给Print(3),最终Print(3)返回0给主函数;也就是说Print函数需要开出三个副本占据内存。
因此递归函数虽然时间复杂度是O(n),但是它的空间复杂度也是O(n)
但是迭代就不一样了,首先什么是迭代,迭代就是一次又一次地重复某些操作,跟递归地作用基本完全一致,但是迭代实际是我们用的最多,在所有语言中地循环就是一种迭代,比如:for,while循环
那么迭代对比递归地优点就出来了,那就是迭代不需要额外地内存开销,那既然迭代必递归要好,那递归的好处是什么呢?
那就是易于思考,因为递归只需要模拟过程就好了,而迭代往往需要想明白过程与结果,比如下面这个例子
请写出汉诺塔难题的程序:(至于汉诺塔是啥请百度搜索一下)
算法:先将n-1个盘子移到2号柱(辅助柱)上,第n个盘子移到3号柱(目标柱),再将n-1个盘子如法炮制,只不过辅助柱变成1号柱而已(非常容易想,且我只需要模拟就可以了)
void Hanoi(int n,char fromtower,char needtower,char totower){ if(n==1) cout<<"move disk"<<n<<" from "<<fromtower<<" to "<<totower<<endl; else{ cout<<"move disk"<<n<<" from "<<fromtower<<" to "<<totower<<endl; Hanoi(n-1,needtower,fromtower,totower); } }
既然我们可以正着想,那必然我们也可以逆着想,而这就是回溯的思想,那么我们也可以用递归来写回溯
来道例题吧,同时我们把难度加大点吧
请写出n位2进制串的所有形式
void binary(int a[],int n,const int all){ if (n<1) { for(int i = 0 ;i<all;i++) cout<<a[i]; cout<<endl; } else{ a[n-1] = 0; binary(a,n-1,all); a[n-1] = 1; binary(a,n-1,all); } }
理解了这个递归就差不多掌握了哟