zoukankan      html  css  js  c++  java
  • [算法] 递归

    编程语言在构建程序时的基本操作有:内置数据类型操作、选择、循环、函数调用等,递归实际属于函数调用的一种特殊情况(函数调用自身),其数学基础是数学归纳法。递归在计算机程序设计中非常重要,是许多高级算法实现的基础

     

    编写递归程序的几个要点:

    1、终止条件:最简单情况(避免无限循环)

    2、递归公式:相邻两次调用间的关系(递归算法核心)

    3、忽略调用具体细节:假设所有调用都会达到终止条件(从思想上接受递归算法的关键)

    4、效率:递归算法有时效率较低,可考虑其他更高效的实现方式(见问题5)

     

    下面我们通过几个典型问题了解递归程序的的写法和思路:

    问题1:求F(n)=1+2+3+...+n

    也可用for循环实现,相比之下递归的代码更加简洁

    从后往前:

    def F(a):
        if len(a)==1:return(a[0])
        return(F(a[1:])+a[0])

    或从前往后:

    def FF(a):
        n = len(a)
        if n == 1:return(a[0])
        return (FF(a[:n-1])+a[n-1])

    效果:

    a=[1,4,6,9]
    print(F(a))
    >> 20

     

    问题2:n条直线最多可以划分的平面个数?

    首先举几个简单的例子,F(1) = 2,F(2) = 4,F(3) = 7

    简单画个图就可以看出,每次划分增加1条直线,实际是在上次划分的基础上增加了n个交点,进而增加了n个平面

    def F(n):
        if n == 1:return(2)
        return(F(n-1) + n)

     

    问题3:求两个正整数的最大公约数

    利用欧几里得算法:若p>q,则p和q的最大公约数等于q和p%q的最大公约数(证明思路:p和q的最大公约数等于p和p-q的最大公约数,也等于p和p-2q的公约数,以此类推直到p和p-nq即p%q)

    终止条件:p被q整除,q=0,p即为所求(任何正整数都可被1整除,故一定能收敛)

    def F(p,q):
        if q == 0:return p
        print(p,q)
        return F(q,p % q)
    print(F(1440,408))
    >> 1440 408
    >> 408 216
    >> 216 192
    >> 192 24
    >> 24

     

    问题4:汉诺塔问题。把圆盘按大小顺序移到另一个圆盘上,每次只能移一个,小圆盘不能放大圆盘上边,如果有64个圆盘,需要挪多少次?

     

    像这种问题如果生想的话估计会把脑细胞耗尽,索性我们有递归大法,可以忽略具体的实现细节:

    终止条件:f(1)=1

    递归公式:f(n)=2f(n-1)+1

    def F(n):
        if n == 1:return 1
        return 2*F(n-1)+1
        
    >>print(F(64))
    >>18446744073709551615

     

    问题5:斐波那契数列(1,1,2,3,5,8,13,21,34...)求和

    def F(n):
        if n == 1 or n == 2:
            return 1
        return(F(n-1) + F(n-2))

    但由于存在重复计算,此程序效率较低,实际开发中通常采用其他方式实现,详见:

    斐波那契数列的5种Python写法

    斐波那契数列的矩阵解法

     

    问题6:编写merge(L1,L2)函数,将两个排好序的小列表合成一个排好序的大列表,如merge([1,2,4],[3,5])=[1,2,3,4,5]

    merge()是归并排序算法中的关键函数,我们在这里用递归实现一下:

    def merge(L1,L2):
        if len(L1) == 0:return(L2)
        if len(L2) == 0:return(L1)
        if L1[0]<L2[0]:
            return([L1[0]]+merge(L1[1:len(L1)],L2))
        else:
            return([L2[0]]+merge(L1,L2[1:len(L2)]))
    
    >>print(merge([1,2,4],[3,5]))
    >>[1,2,3,4,5]

    当然merge()有许多其他的实现方法,大家可自行探索

    掌握了递归思想后,我们就可以写出更加简洁、高效的程序了。在后续算法的学习中,要注意递归思想在不同条件下的体现,熟练运用

  • 相关阅读:
    Servlet CDI Example Analysis
    JSON续
    JSON
    Ubuntu 下安装 MySQL
    Filter介绍
    Annotation相关
    Container、Injection
    Java buildTools
    Http协议
    URI URL URN 的区别
  • 原文地址:https://www.cnblogs.com/cxc1357/p/10324179.html
Copyright © 2011-2022 走看看