zoukankan      html  css  js  c++  java
  • 重新认识递归

    什么是递归?

      递归,就说函数在运行的过程中调用自己。

    代码如下:

    def recursion(n):
        print(n)
        recursion(n+1)
    recursion(1)

    出现的效果,就是这个函数在不断的调用自己,每次调用n+1相当于循环。

    结果如下:

    可是为何执行了900多次就出错了?还说超过了最大递归深度限制,为什么要限制?

    通俗讲,每个函数在调用自己的时候,还未退出,占内存,多了会导致内存崩溃。

    本质上讲,在计算机中,函数调用是通过栈这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出。

     递归的特点

       通过现象看本质,下面是用递归写的程序,让10不断除以2,直到0为止。

    def cacl(n):
        print('--->', n)
        if int(n/2) > 0:
            cacl(int(n/2))
        else:
            print('---')
        print(n)
    
    cacl(10)

    运行结果:

     为何结果先打印10、5、2、1,然后又打印了1、2、5、10呢? 打印10、5、2、1可以理解,因为函数在一层一层的调用自己,但1、2、5、10是什么逻辑呢?因为当前函数在执行过程中又调用了自己一次,当前这次函数还没结束,程序就又进入了第2层函数调用,第2层还没结束就又进入了第3层,直到n/2>0不成立时才停止,此时问你,程序现在结束了吗?no,no,现在递归已经走到最里层,最里层的函数不需要继续递归了,会执行下方的else 判断。

     

    打印的时1,然后最里层的函数就结束了。结束后会返回到之前调用它的位置,即上一层,上一层打印的时2,再就是5、10,即最外层函数,然后结束。

    总结:

    递归就是一层一层进去,还要一层一层出来。

     最后的总结:

      1. 必须有一个明确的结束条件,要不就会变成死循环,最后系统down。

      2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

      3. 递归执行效率不高,递归层次过多会导致栈溢出

     递归有什么用?

     求阶乘

       任何大于1的自然数n阶乘表示方法:

       n! = 1*2*3*4*....*n

       n! = n *(n-1)!

    用递归代码来实现:

    def fun(n):
        if n == 0:
            return 1
        return n * fun(n -1)
    
    d = fun(0)
    print('*******',d)

    二分查找

    我们首先引入这样一个问题:如果规定某一科目成绩分数范围:[0,100],现在小明知道自己的成绩,他让你猜他的成绩,如果猜的高了或者低了都会告诉你,用最少的次数猜出他的成绩,你会如何设定方案?(排除运气成分和你对小明平时成绩的了解程度)

    ①最笨的方法当然就是从0开始猜,一直猜到100分,考虑这样来猜的最少次数:1(运气嘎嘎好),100(运气嘎嘎背);

    ②其实在我们根本不知道对方水平的条件下,我们每一次的猜测都想尽量将不需要猜的部分去除掉,而又对小明不了解,不知道其水平到底如何,那么我们考虑将分数均分

      将分数区间一分为2,将第一次猜的分数将是50,当回答低了,将分数区间从【0,100】确定到【51,100】;

      当回答高了,将分数区间从【0,100】确定到【0,50】.这样一下子就减少了多余的50次猜想(从0数到49)(或者是从51到100)。

    ③那么我们假设当猜完50分之后答案是低了,那么我们需要在【51,100】分的区间内继续猜小明的分数,同理,我们继续折半,第二次我们将猜75分,当回答是低了的时候,我们将其分数区域从【51,100】确定到【76,100】;当回答高了的时候,我们将分数区域确定到【51,74】。这样一下子就减少了多余的猜想(从51数到74)(或者是从76到100)。

    ④就此继续下去,直到回复是正确为止,这样考虑显然是最优的

    代码如下:

    data_set = list(range(101))
    
    def b_search(n,low,high,d):
        mid = int((low+high)/2)
        if low == high:
            print('not found')
            return
    
        if d[mid] > n:
           print('to left :', low,high ,d[mid])
           b_search(n, low, mid, d)
        elif d[mid] < n:
            print('to right :', low, high, d[mid])
            b_search(n, mid+1, high, d)
        else:
            print('find it ', d[mid])
    
    b_search(88,0,len(data_set),data_set)

    运行结果:

  • 相关阅读:
    USACO2.24 Party Lamps
    hdu3811 Permutation
    局部视图Partial
    动态修改a标签的css样式
    .net 记住用户名和密码
    C#枚举
    学习存储过程的时候参看的两个DVBBS的存储过程和两个初步了解后自己写的存储过程(带分页的)
    js 几种常用的表单输入判断
    AJAX+.net实现无刷新搜索,无须提交,边输边查
    ifream中的数据传递
  • 原文地址:https://www.cnblogs.com/lhly/p/11535848.html
Copyright © 2011-2022 走看看