算法与数据结构 | 深入理解栈与递归

1.如何理解递归?

递归是一种全新的思维方式,初学递归总会有知其然却不知其所以然的感觉,这里我们可以从循环入手,探讨递归与循环的内在差别。

理论上:所有的递归都可以用循环实现,但实际上有的算法因为循环次数过多,很难转换。(如:汉诺塔问题)。

我们先来假设这样一个场景

有一个大盒子,打开,里面还是一个盒子,再打开,还是盒子,直到你打开很多次后,最后一个小盒子里放了颗钻石。

1.如果用循环实现
因为你打开的次数过多,所以你并不能清晰的记住自己打开了几个盒子,因此这里无法使用for循环,但是可以使用while循环,过程大致为:
流程
创建要查找的盒子堆->只要盒子堆不空->打开一个盒子
->如果还是盒子(返回步骤2)
->如果是钻石(万事大吉)
伪代码

def look_for_diamond(big_box):
	pile = big_box.make_a_pile_to_look()
	while pile is not empty:
	box = pile.grab_a_box()
	for temp in box:
		if temp.is_a_box():
			pile.look_for_again(temp)
		if temp.is_diamond():
			print "get the diamond!"

2.如果用递归实现
流程
检查盒子
->如果是盒子(返回步骤1)
->如果是钻石(大功告成)
伪代码

def look_for_diamond(box):
	for temp in box:
		if temp.is_a_box():
			look_for_diamond(temp)
		elif temp.is_a_key():
			print "get the diamond!"

相对于循环来说,递归的步骤变少且逻辑更加清晰,但性能上没有什么优势,到底使用递归还是循环要取决于具体的问题,一般来讲循环性能可能更高,而递归更清晰明了。

2.基线条件和递归条件

初用递归,往往会不慎造成死循环,从而导致函数出错,因此编写递归函数时,必须告诉它何时停止递归,因此,每个递归函数都有两部分:基线条件(base case)和递归条件(recursive case)。基线条件指函数不在调用自己,而递归条件指函数继续调用自己。
如:

def countdown(i):
	print i
  if i<=1:  //基线条件
	return
  else:     //递归条件
    countdown(i-1) 

3.调用栈

向一个玻璃杯里放乒乓球,放入1号再放入2号再放入3号,然后取出的顺序则为3,2,1,这种先进后出的数据结构即为栈。那递归与栈又又什么关系呢?其实递归函数就是在调用栈!
如(阶乘运算):

def fact(x) :
	if x == 1:
		return 1
	else:
		return x*fact(x-1)

当我们输入3的时候,即执行3fact(3-1)
此时继续执行fact(3-1) == fact(2) 则执行2
fact(2-1)
此时继续执行fact(2-1)==fact(1)==1,返回1
从而得到 123 = 3!
其实这里的3fact(3-1)就是1号乒乓球,2fact(2-1)就是2号乒乓球,1就是3号乒乓球。
这便是一个重要的概念:当一个函数里面要调用另一个函数时,当前函数暂停并处于未完成状态,即此时函数的所有变量的值都还在内存中,只有当执行完了调用的函数时,才会回到当前函数,并继续向下执行,这个过程就调用了栈!

切记:在一个函数中调用另一个函数,调用的函数是无法访问其他函数中的变量的,就好比2号乒乓球不能访问1号和3号乒乓球里面的东西一样。

4.总结

栈是计算机自身在调用函数时自己开辟出来的,因此不需要自己去实现,使用栈虽然很方便,但是也不可避免的要占用一定的内存,如果栈很高,就意味着计算机为此存储了大量函数调用的信息,如果递归深度过高,甚至会造成计算机死机,在这种情况下,你有两种处理方法:
1).转换为循环
2).使用尾递归。尾递归是一种高级的方法,我们在后续讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值