Loading

函数递归调用


函数的递归调用

在调用一个函数的过程中直接或间接地调用到了本身。函数的递归调用本质就是一个循环的过程(用函数实现的循环)。

递归调用必须在满足某种条件下结束,不能无限递归调用下去。


1、直接调用自身:

def f1():
    print('from f1')
    f1()

2、间接调用自身:

def f1():
    print('from f1')
    f2()
    
def f2():
    print('from f2')
    f1()

python不是一门函数式编程语言,无法对递归进行尾递归优化。尾递归优化,即在函数的最后一步(而非最后一行)调用自己。

在Python中,每调用一次函数就会在内存产生一个局部名称空间,所以为了防止递归死循环造成内存溢出,Python对递归的最大深度做了限制,默认为1000层。

# 查看最大深度。
import sys
print(sys.getrecursionlimit())

# 设置最大深度,但仍受限于操作系统栈大小的限制,不推荐修改。
sys.setrecursionlimit()

递归的两个阶段

例如要求出第一个人年龄,这个人比第二个人大10岁,第二个人又比第三个人大10岁,第三个人比第四个人大10岁,第四个人比第五个人大十岁,而第五个人的年龄为18岁,那么我们要求第一个人的年龄,就是:

man1 = man2 + 10
man2 = man3 + 10
man3 = man4 + 10
man4 = man5 + 10
man5 = 10

用代码来写就是这样:

def age(n):
    if n == 1:
        return 18
    return age(n-1) + 10

执行过程:

回溯阶段

不断的向下一层函数递进,这个过程称为回溯。

print(age(5))
# age(5) -> age(4) -> age(3) -> age(2) -> age1(1)

递推阶段

满足结束条件,逐层返回值,这个过程称为递推。

age(5) <- age(4) <- age(3) <- age(2) <- age1(1)
58     <-  48    <- 38     <- 28     <- 18

递归应用

在写代码时,如果出现某个功能需要重复调用自身,这个时候就可以使用到递归。

二分法

对一个从小到大排序的有序数字元素列表,查找某个值在列表中的所在位置。若使用遍历查找,那么时间复杂度为O(n)。我们可以使用二分法查找,每次将值与列表中间的元素比较,若值比中间元素大,则下次从右边查找即可;若值比中间元素小,下次从左边查找即可。每次将值与列表的中间值比较,直到找到该值或无该值。

列表为:

l = [-4,-1,0,1,5,8,9,2,8,12,62,23,63]

Python实现二分法:

def dichotomy(n,num_list):
    # 对列表排序。
    num_list.sort()
    
    if len(num_list) == 0:
        # 表示列表为空,无该值.
        return
    
    median = len(num_list) // 2
    if n > num_list[median]:
        # 如果值大于中间值。
        new_list = num_list[median+1:]
        dichotomy(n,new_list)
        
    elif n < num_list[median]:
        # 如果值小于中间值。
        new_list = num_list[:median]
        dichotomy(n,new_list)
        
    else:
        # 不大不小表示找到该值。
        print(f'{n} index is {median}')

阶乘

一个正整数的阶乘factorial)是所有小于及等于该数的正整数的积,并且0的阶乘为1。自然数n的阶乘写作n!。

任何大于等于1 的自然数n 阶乘表示方法:
n! = n * n(n-1)!

Python代码实现:

def factorial(n):
    if n == 1:
        return n
    return factorial(n-1) * n
posted @ 2020-08-05 22:24  吃了好多肉  阅读(616)  评论(0编辑  收藏  举报