算法之递归
递归思想
递归就是函数自己调用自己,会使代码逻辑很清晰,但是Stack Overflow上有说的一句话:“如果使用循环,程序的性能可能更高;如果使用递归,程序可能更容易理解。如何选择要看什么对你来说更重要。
很多排序算法都用到了递归,例如快速排序,归并排序等,具体排序算法代码参考我之前写的博客python实现常见排序算法
基线条件和递归条件
基线条件
递归必须有一个终止条件,避免形成无线循环,这个条件就叫做基线条件。
举例一般都是一些特殊情况,比如快排时的列表是空列表或者只有一个元素就不需要排序就退出函数即可,这就是基线条件
递归条件
指的是函数自己调用自己
简单的例子
def countdown(i):print(i,end=',')if i <= 0: # 基线条件returnelse: # 递归条件countdown(i-1)
countdown(3) # ==> 3,2,1,0,
栈
简单说一下栈:类似枪的弹夹,只能压入子弹(插入数据),弹出子弹(删除并读取),子弹只能后先压入的最后出来(first in last out)。
调用栈(call stack)
计算机在内部使用被称为调用栈的栈
函数举例
def greet(name):print 'hello' + name + '!'greet2(name) # 调用hello2进行问候print 'getting ready to say bye...'bye() # 调用bye进行拜拜def hello(name):print 'Have you eaten yet, '+ namedef bye()print 'ok, bye'
内存角度介绍上述函数hello被调用后的计算机处理过程
调用hello计算机分配空间给这个函数存储函数名和name=maggie,这里给命个名叫greet内存块
hello内部调用了hello2,同上,计算机一样分配的内存给他,叫greet2内存块
如下图,打印Have you eaten yet miggie后调用的函数被返回,此时greet2内存块倍弹出。
hello内部调用了bye,同上,计算机一样分配的内存给他,叫bye内存块
bye内存块进来又压在了greet内存快上,打印完ok,bye后又弹出了
然后整个函数结束,greet内存块也被弹出
这个栈用于存储多个函数的变量被称为调用栈
递归调用栈
递归函数也使用调用栈,直接看代码
def fact(x): # jiecheng(3)--> 3! = 3 * 2 * 1 求出3的阶乘if x == 1:return 1return x * fact(x-1)
有三个fact的调用,等fact(1)调用结束被弹出,依次弹出,注意每个fact调用都有自己的x变量,在一个函数调用中不能访问领一个的x变量。
这个栈包含了未完成的函数调用。
缺点:使用栈虽然很方便,但是也要付出代价:存储详尽的信息可能占用大量的内存。每个函数调
用都要占用一定的内存,如果栈很高,就意味着计算机存储了大量函数调用的信息。在这种情况
下,有两种选择。
- 重新编写代码,转而使用循环。
- 使用尾递归。这里不讨论,感兴趣可以去查。
小结
- 递归指的是调用自己的函数。
- 每个递归函数都有两个条件:基线条件和递归条件。
- 栈有两种操作:压入和弹出。
- 所有函数调用都进入调用栈。
- 调用栈可能很长,这将占用大量的内存。