在做leetcode的时候,遇到了二叉树的遍历,用过许多方法之后,最终着手于利用递归方法来遍历二叉树,递归算法在实现上相较于其他的算法来得更为简单,但是递归对时间和空间的占用其实是比较高的,所以当选择递归的时候,我们应该考虑是否有更加便捷的非递归方法。
那么什么情况下我们可以有效的使用递归呢,递归和循环又有什么关系呢,接下来我将会结合自身经历粗浅的谈谈递归。
使用递归的条件:用一种通俗不完全的说法来讲,递归可以说是一种调用自己的思想,当然这种说法并不准确,我们知道递归还存在交叉调用的情况,这里辩不过多阐述了。既然递归是调用了自己,所以必要的一个条件就是进入递归的部分一定要在形式上保持一致。
递归和循环的区别在哪呢:有人说既然我已经掌握了循环,为什么还要用递归来多此一举呢,然而递归和循环还是有很大区别的,在我所遇到的各种问题中,所有可以用循环来解决的问题,用递归都可以很好的实现,然而用递归可以实现的问题,我们有时用循环就不能实现了。另外递归主要注重问题的结果,而循环主要关注问题的过程,我们可以从各自的实现中知道,循环主要是从过程中来对各个变量进行修改从而达到控制变量的结果。而递归则是对问题每次递归的结果进行讨论。来达到对变量的控制。
一些经典问题关于递归的讨论:
1.汉诺塔问题:
汉诺塔问题可以说是递归的一个经典问题了,很多递归入门的书上都有对汉诺塔问题的叙述。相信大家对这个问题已经有了很多的
了解了,所以我就对汉诺塔问题直接开始表述我的解决思路。
很显然,当我们对要将n个盘子移动到目标柱子时,我们只需要考虑将n-1个盘中移动到目标柱子,明显的,我们可以通过递归来解决
这个问题。
假设柱子为1,2,3(依次3为当前位置,过渡柱子,目标柱子),递归方法为:method(int n,1,3,2),表示为将n个盘子从1通过2移动到3
便有method(int n,1,3,2):
if(n==1) move n 从1移动到3;
else{
method(n-1,1,3,2);
method(n-1,2,3,1)这行主要是为了让递归在形式上保持一致。
}
2.斐波那契数列:
如果大家觉得这个名字很数学,很高大上,不好理解的话,我建议可以看成另一个问题。兔子生孩问题(自己随便取的名字),假设我们有一对兔子,兔子到第三个月开头就会生下一对小兔子,如果兔子不死,求不第n个月有多少对兔子。
显然我们可以看出兔子和对应的数量关系为:1,1,2,3,5,8,13.......,从中我们得出规律,从第三个开始,每一个就是前两个之和,这
很显然可以使用递归来实现:
method(n):
if(n==1||n==2) return 2;
return method(n-1)+method(n-2);
这样斐波那契数列苏烈就可以很好的实现了。
3.遍历二叉树:
这是在leetcode上所遇到的一个问题,其实当时是并不需要我遍历整个二叉树,但是处于对知识额运用,我用了递归的方法来
二叉树,我这里采用的是中序遍历,前序和后序实现差不多,大家可以自己思考,首先TreeNode已经有题目自定了。
实现如下:
method(root)
LinkedList list = new LinkedList();
if(root==null) return;
id(root.left!=null) method(root.left);
list.add(root);
if(root.right!=null) method(root.right);