精华内容
下载资源
问答
  • 广告关闭腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元!而对应的中文翻译 ”递归“ ... python递归常见使用汉诺塔python第二十二课:python递归函数树状pytho...

    o55g08d9dv.jpg广告关闭

    腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元!

    而对应的中文翻译 ”递归“ 却表达了两个意思:”递“+”归“。 这两个意思,正是递归思想的精华所在。 从这层次上来看,中文翻译反而更达意。 递归是静中有动,有去有回。 循环是动静如一,有去无回。 python递归常见使用汉诺塔python第二十二课:python递归函数树状python第二十二课:python递归函数谢尔宾斯基...

    参考:https:pythonspot.comrecursionhttps:www.python-course.eurecursive_functions.php一、递归函数两大要素--终止条件和递归方程1、递归方程,即递归调用的方法递归通俗的说就是在函数内部自己调用自己,如何调用就是递归方程。 以以下的sum(n)求和函数递归实现方式为例,递归调用方式就是返回n+sum(n-1)...

    g0xgugers9.jpeg

    一个函数在函数体内部调用自己,这样的函数称为递归函数,递归的次数在python是有限制的,默认递归次数是997次,超过997次会报错:recursionerror.? 一. 递归函数案例案例一:计算数字n的阶乘(举个栗子:9的阶乘 = 9*8*7*6*5*4*3*2*1)# ! usrbinenv python# -*- coding:utf-8 _*-@author:何以解忧@blog(个人博客...

    递归函数 在函数内部,可以调用其他函数。 如果一个函数在内部调用自身本身,这个函数就是递归函数。 举个例子,我们来计算阶乘 n! = 1 * 2 * 3 * ... * n,用函数 fact(n)表示,可以看出: fact(n) = n! = 1 * 2 * 3 * ... * (n-1) * n = (n-1)! * n = fact(n-1) * n 所以,fact(n)可以表示为 n * fact(n-1),只有n=...

    使用python写的递归程序如果递归太深,那么极有可能因为超过系统默认的递归深度限制而出现runtimeerror:maximum recursion depth exceeded in comparison的错误, 解决方法很简单,人为将系统设定的递归深度设置为一个较大的值即可:import syssys.setrecursionlimit(1000000) #括号中的值为递归深度...

    python之递归函数 好久没有更新内容了,也好久没有给大家打个招呼了,小白想死你们了。 今天跟大家说说python中的递归函数。 python是支持递归函数的。 简单地说,一个递归函数就是直接或间接地调用自身的函数,并且要有退出条件。 枯燥的概念令人生厌,我们直接来个例子看看递归函数是如何工作的。 例如我们对一个...

    035ewvmtbt.jpeg

    python之递归函数好久没有更新内容了,也好久没有给大家打个招呼了,小白想死你们了。 今天跟大家说说python中的递归函数。 python是支持递归函数的。 简单地说,一个递归函数就是直接或间接地调用自身的函数,并且要有退出条件。 枯燥的概念令人生厌,我们直接来个例子看看递归函数是如何工作的。 例如我们对一个...

    print(n)returncalc(n) calc(10)执行输出一堆10之后,报错 recursionerror:maximum recursion depth exceeded while calling a pythonobject提示调用该对象超过最大递归深度查看python默认的最大递归深度,需要用sys模块importsysprint(sys.getrecursionlimit())执行输出 1000 这个深度,可以通过setrecursionlimit()...

    27p16mrszp.gif

    递归:一种直接直接或者间接调用自身算法的过程递归在调用的过程中,是在上一层循环还没有结束直接进入下一层,多层嵌套调用实现调用例1:? 1 def func(n): 2 print(n) 3 if n > 1:4 t = func(n 2) 5 print(t, t) # 当循环结束,会一层一层退出循环,退出一层打印一层 6 else:7 print(已经是最小了) 8 print(n, n) 9 ...

    obvy0lu01a.png

    每次进入更深一层递归时,问题规模相比上次递归都应有所减少3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用时通过栈(stack)这种结构数据实现的,每当进入一个函数调用栈就会多一层栈帧,每当函数返回,栈就会减一层栈帧。 由于栈帧不是无限的,所以递归调用的次数过多,会导致栈溢出)...

    output:-----请输入9或5,显示hello world9hello world输入1继续,输入0停止! 1请输入9或5,显示hello world9hello world输入1继续,输入0停止! 5请输入9或5,显示hello world9hello world输入1继续,输入0停止! 0end----- 承接matlab、python和c++的编程,机器学习、计算机视觉的理论实现及辅导,本科和硕士的均可...

    每次进入更深一层递归时,问题规模相比上次递归都应有所减少3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧, 每当函数返回,栈就会减一层栈帧。 由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)...

    递归 函数自己调用自己,递归的入口(参数) 和 出口(return)语法:def func():print(我是递归) func() func() # 官方显示最多到1000. 但不会跑到1000,实际到998# 树形结构的遍历 import osdef func(lujing, n):lis = os.listdir(lujing) # 打开文件夹,列出文件夹内的所有文件名 for el in lis:# el 为文件的名字 # ...

    6trdtrdy9l.png

    递归函数初识递归函数递归函数的定义:在一个函数里再调用这个函数本身python为了考虑保护内存占用情况,有一个递归深度的限制。 探究递归的默认最大深度:def foo(n):print(n) n += 1 foo(n)foo(1)强制的将递归层数控制在了997,此后会报错,报错只是计算机为了保护内存。 当然了,997是python为了我们程序的内存...

    print(from foo) foo() foo()间接调用def bar(): print(from bar) foo() def foo():print(from foo) bar() foo()递归分为两个阶段1、回溯: 注意:一定要在满足某种条件结束回溯,否则的无限递归2、递推 总结:1、递归一定要有一个明确地结束条件2、没进入下一次递归,问题的规模都应该减少3、在python中没有尾递归...

    print(x)print_li(li)建立打印函数print_li(li),用for循环判断列表中的每一项,如果该项还是列表,则递归调用函数自身继续判断,如果不是列表,则直接输出即可。 补充拓展:python 多个列表对应项求和两个列表求和有时候我们会有这样的需求:两个列表和,需要求和得到,很多人可能会创建个空列表然后for循环使用...

    为了感受python的列表生成器的威力,写了个简单的程序——递归求矩阵的行列式,效率可能没numpy高,欢迎各位指正。 def det(m): if len(m)...

    通常,我们都是自上而下的思考问题,递归则是自下而上的解决问题——这就是递归看起来不够直观的原因。 那么,究竟什么是递归呢? 让我们先从生活中找一个例子。 我们都有在黑暗的放映厅里找座位的经验:问问前排的朋友坐的是第几排,加上一,就是自己当前所处位置的排号。 如果前排的朋友不知道自己是第几排,他可以...

    1drmxout70.jpeg

    一个半路转行的数据挖掘工程师【知乎专栏】:https:zhuanlan.zhihu.compypcfx全文3345字 | 阅读需要5分钟递归是一个很经典的算法,在实际中应用广泛,也是面试中常常会提到的问题。 本文就递归算法介绍如何在python中实现递归的思想,以及递归在python中使用时的一些注意事项,希望能够对使用python的朋友提供一些...

    hk7e1gc3fz.png

    算法的复杂度,表示代码的运行效率,可以用一个大写的o加括号来表示,比如o(1),o(n)递归 递归就是在函数中调用本身,大多情况下会给计算机增加压力,但是有时又很有用。 先上图,这个推得高高类似塔状的汉诺塔游戏。? ①把a柱子的盘子,移动到c柱子上,最少要移动几次,大盘子只能在小盘子下面。 思考:要将所有盘子...

    展开全文
  • python递归函数什么是递归?递归,就是在函数运行中自己调用自己代码示例:def recursion(n): # 定义递归函数print(n) # 打印nrecursion(n+1) # 在函数的运行种调用递归recursion(1) # 调用函数这个函数在不断的自己...

    python递归函数

    什么是递归?

    递归,就是在函数运行中自己调用自己

    代码示例:

    def recursion(n): # 定义递归函数

    print(n) # 打印n

    recursion(n+1) # 在函数的运行种调用递归

    recursion(1) # 调用函数

    这个函数在不断的自己调用自己,每次调用n+1,看下运行结果:

    1

    2

    .....

    998Traceback (most recent call last):

    File "D:/py_study/day08-函数/python递归函数md/01-什么是递归.py", line 11, in

    recursion(1)

    File "D:/py_study/day08-函数/python递归函数md/01-什么是递归.py", line 9, in recursion

    recursion(n+1)

    File "D:/py_study/day08-函数/python递归函数md/01-什么是递归.py", line 9, in recursion

    recursion(n+1)

    File "D:/py_study/day08-函数/python递归函数md/01-什么是递归.py", line 9, in recursion

    recursion(n+1)

    [Previous line repeated 993 more times]

    File "D:/py_study/day08-函数/python递归函数md/01-什么是递归.py", line 8, in recursion

    print(n)

    RecursionError: maximum recursion depth exceeded while calling a Python object

    Process finished with exit code 1

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

    通俗来讲,是因为每个函数在调用自己的时候,还没有退出,占内存,多了肯定会导致内存崩溃.

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

    我们还可以修改递归深度,代码如下:

    import sys

    sys.setrecursionlimit(1500) # 修改递归调用深度

    def cacl(n):

    print(n)

    cacl(n+1)

    cacl(1)

    运行结果如下:

    1

    2

    ......

    1498Traceback (most recent call last):

    File "D:/py_study/day08-函数/python递归函数md/02-修改递归深度.py", line 11, in cacl

    cacl(n+1)

    File "D:/py_study/day08-函数/python递归函数md/02-修改递归深度.py", line 11, in cacl

    cacl(n+1)

    File "D:/py_study/day08-函数/python递归函数md/02-修改递归深度.py", line 11, in cacl

    cacl(n+1)

    [Previous line repeated 995 more times]

    File "D:/py_study/day08-函数/python递归函数md/02-修改递归深度.py", line 10, in cacl

    print(n)

    RecursionError: maximum recursion depth exceeded while calling a Python object

    让我们以最经典的例子说明递归

    # 计算n! # 相信很多人都学过阶乘,比如5! = 5*4*3*2*1 n! = n*(n-1)*(n-2)*...*1,那么在递归中该如何实现呢?

    # 1.打好函数的框架

    def factorial(n): # 定义一个计算阶乘的函数

    pass # 不做任何操作

    factorial(3) # 调用

    # 2.考虑两种情况,如果n=1,那么1的阶乘就是1了,如果这个传递的参数大于1,那么就需要计算继承了.

    def factorial(n):

    if n == 1: # 判断如果传递的参数是1的情况

    return 1 # 返回1,return代表程序的终止

    res = factorial(1) # res变量来接受函数的返回值

    print(res) # 打印

    2.1如果传递的参数不是1,怎么做?

    def factorial(n):

    if n == 1:

    return 1

    else:

    # 5*4! = 5*4*3! = 5*4*3*2!

    return n * factorial(n-1) # 传递的参数是n,那么再次调用factorial(n-1)

    res = factorial(1)

    print(res)

    举例2:

    # 让10不断除以2,直到0为止。

    int(10/2) = 5

    int(5/2) = 2

    int(2/2) = 1

    int(1/2) = 0

    # 1.同样第一步先打框架

    def cacl(n): # 定义函数

    pass

    cacl(10)

    # 2.那么我们想从10开始打印然后一直到0,怎么做?

    def cacl(n): # 定义函数

    print(n)

    cacl(10)

    # 3.已经把打印的值传递进去了,那么就是在里面操作了

    def cacl(n): # 定义函数

    print(n) # 打印传递进去的值

    v = int(n /2) # n/2

    if v>0: # 如果v还大于0

    cacl(v) # 递归,把v传递进去

    print(n) # 打印v,因为已经调用递归了,所以此时的n是v

    cacl(10)

    运行结果如下:

    10

    5

    2

    1

    1

    2

    5

    10

    怎么输出会是这样呢?我刚刚说过,什么是递归?递归就是在一个函数的内部调用函数本身,我们打个比方,递归一共有3层,那么第二层就是调用第一层的结果,第三层又去调用第二层的结果,所以!当上面这个程序运行时,第一次打印的是10,然后除上2,等于是5,再继续除,一直到了1,然后1/2是等于0的,此时就没有调用了递归,但是我还在调用上一层函数,就需要把这个数给返回出来,所以就变成后来的1,2,5,10了。

    递归特性

    1.必须要有一个明确的结束条件, 否则就变成死循环导致栈溢出

    2.每次进入更深一层递归时,问题规模相比上次递归都应有所减少,这句话的以上就是说,每进入一次递归,就会解决一些东西,数据量就会越来越小,最终解决了所有的问题,如果进入一次递归没有解决问题,那么不管递归多少层都没有意义,直到导致栈溢出。

    3.递归效率比较低,递归层次过多会导致栈溢出,意思是:每当进入一次函数调用,栈就会加一层栈帧,每当函数返回,就减少一层栈帧,由于栈不是无限大小的,所以,递归调用的次数过多,会导致栈溢出。

    那么有没有优化方式呢?肯定是有的

    尾递归

    我在知乎上找了一个特别有意思的例子来说明下什么是尾递归:

    def story() {

    从前有座山,

    山上有座庙,

    庙里有个老和尚,

    一天老和尚对小和尚讲故事:story() // 尾递归,进入下一个函数不再需要上一个函数的环境了,得出结果以后直接返回。

    }

    def story() {

    从前有座山,

    山上有座庙,

    庙里有个老和尚,

    一天老和尚对小和尚讲故事:story(),小和尚听了,找了块豆腐撞死了 // 非尾递归,下一个函数结束以后此函数还有后续,所以必须保存本身的环境以供处理返回值。

    }

    尾递归,进入下一个函数不再需要上一个函数的环境了,得出结果以后直接返回。

    def cal(n):

    print(n)

    return cal(n+1) # return代表函数的结束

    cal(1) # 这个会一直打印,直到导致栈溢出

    # 调用下一层的同时,自己就退出了

    展开全文
  • 递归再特定的场景下,非常实用,巧妙的递归设计能解决很多问题,文章主要列出了递归的各种思想和丰富的使用案例!

    递归剖析

    • 递归真的很重要,之前学的时候,学的一知半解,以为真正了解,每次想到递归,就记得一句:返回给函数的调用者,嗯?函数调用者,你是说外部,还是内部啊?疑问太多了,还有就是被告知一句:递归能解决的问题,循环都能解决,所以就更加不重视递归了!直到接触算法后,在解决问题时,最快,最容易理解的解法就是递归,但是此时的递归却是看不太懂为什么要这样做!我先来说下,在算法中遇到可以用递归轻松完成的:希尔排序、归并排序、快速排序、反转链表及各种反转问题、二叉树的深度遍历、二叉树的各种题基本可以用、全排列…还有算法步骤里需要用到,太多了,所以,递归非常重要!“To iterate is human, to recurse divine 迭代是人,递归是神”,接下来,我也是看了很多算法书和视频,重点来整理下递归!

    递归的两个过程

    • 首先“递归”包括两个过程:递“去”的过程,“归”回的过程!先从一个简单的递归函数讲起
    def di_gui(n):
        print(n, "<===1====>")
        if n > 0:
            di_gui(n - 1)
        print(n, '<===2====>')
    
    
    di_gui(5) # 外部调用后打印的结果是?
    
    • 递归的执行过程:首先,递归会执行“去”的过程,只需要满足终止条件,就会一直在函数内,带着更新的参数,调用函数自身,注意:到内部调用函数, 以下面的代码不会被执行,而是暂停阻塞;此时 随着函数每调用一次自身,还没有触发 返回值和到达终止条件,等同于在原来的基础上不断“向下/向内”开辟新的内存空间,记住,每次调用一次函数,就不是处在同一空间(想象下《盗梦空间》里的情景,梦中梦,都是处于不同的空间)
      在这里插入图片描述

    • 什么时候“递”去的过程结束?记住有两种情况>>> 一是:当前这层空间函数全部执行结束(终止条件),二是:执行到了return 返回值,直接返回

    • 重点来理解下,首先是一,看上面的列子,例子中没有return,但是不断的调用后,最终还是停止了,因为最后n=0时,di_gi(0)还是去调用,从上往下执行时,遇到if n>0 它被终止了,走不下去了,表明,自己能到达的这层空间已经全部执行完毕;接下来请原地返回吧,返回到哪里?返回到函数的调用者,好我们返回到 di_gui(0),把“到内部调用函数” 以下的代码全部执行完;执行完,看代码走到末尾,以为走出了最外层函数?注意了,此时它所处的空间并不是最外层哦,因为之前它被调用就在空间里面,所以回到的是 di_gui(1)的这一层空间,现在才是真正的开始“回”,所以继续把di_gui(1)的这一层空间,“到内部调用函数”以下的代码全部执行完,回到di_gui(2)的这一层空间…直到到达最开始 从外部调用,让参数5进入的最外层空间位置,才走出来!表示《盗梦空间》里,柯布醒了!
      在这里插入图片描述
      回来看下,代码输出的结果:5 4 3 2 1 00 1 2 3 4 5 ( 注意00这两个是在同一层空间哦)
      在这里插入图片描述

    • 从内存角度(本质)来分析:每调用一次函数,都会单独开辟一份栈帧空间,递归函数就是不停的开辟和释放栈帧空间的过程,具体来理解下:一个普通函数从执行到结束,就是一个开辟空间和释放空间的过程;而递归函数是在调用最外层函数时,先开辟一个最外层空间,每调用一次自身,就会在最外层空间内,再自己开辟本次的空间(所以递归耗内存)(还有一种说法是,不断的本次空间的基础上再开辟空间,等于是不断的嵌套,其实这两种说法本质上是一样的,因为信息都可以做到不共享),空间之间如果不通过参数传递或者用return 返回值,信息是不共享的,如下图↓↓↓

    在这里插入图片描述
    在这里插入图片描述

    • 递归的数据共享情况:递归每一层间的数据是独立的,不共享,但是可以通过参数或者返回值来形成共享,参数具体在传入的是“引用类型”(比如列表)

    • 递归 必须要有一个出口,如果没有出口就会重复调用,不断的开辟栈帧空间

    # 获取最大递归层数:
    import sys
    res=sys.getrecursionlimit()
    print(res) # 结果:1000
    # sys.setrecursionlimit(800) 可以自己设置最大递归层数
    
    • 解释含有 return 返回值的递归,记住 return的返回流程是:先计算,再返回 ,来看下一段求阶乘的代码:
    def jie_cheng(n):
        if n <= 1:
            return 1
        return n * jie_cheng(n - 1)
        
    print(jie_cheng(5))
    

    在这里插入图片描述

    • return 是返回到函数调用者,递归函数和普通函数也是一样的,所以递归最后一层空间走到尽头(一是:指向完毕,二是:遇到return,回顾一下而已)遇到return,就要开始返回了,返回到它的调用者(即是阻塞的位置),直到回到最外层空间
    • 如果上面的内容看懂了的话,试着解析下:下面这段代码的执行流程
    def get_num(num):
        if num > 2:
            get_num(num - 1)
        print(num)
    
    
    get_num(4) # 输出结果为:2 3 4
    

    在这里插入图片描述

    代码变化一下:

    def get_num(num):
        if num > 2:
            get_num(num - 1)
        else:
            print(num)
    
    
    get_num(4) # 输出结果为 2
    
    '''
    解析一下:加了else后,首先代码区有两个分支,
    在num>2时,执行会有递归,当n=4 是开辟一层空间;
    n=3时开辟一层空间,此时 get_num(2) 再开辟一个空间,
    当它从上往下执行过程中,在他本层空间遇到if num>2 不成立,所以走分支 else,直接打印出来;
    此时代码还没结束,回到上一层空间,num=3, num>2 已经进入了if 不会走else,
    num=4 也不会走else,所以这两层空间没有值输出!
    '''
    

    return 返回值 详解

    • 上面这一大部分,就算是递归入门了,接下来才刚刚开始哦!还要继续讲 return ;先来看下这几段代码:求全排列的一部分递归代码,试着分别写出运行结果,并依次分析原因↓↓↓
    # 例1:
    def fullpermutation(list):
        if list is None:
            return None
        if len(list) == 1:
            return [list]
        res = []
        pivot = list[0]
        remain = fullpermutation(list[1:])
        print(remain)
    
    
    print(fullpermutation([1, 2, 3]))  
    '''
    输出结果为:
    [[3]]
    None
    None
    '''
    
    • 递归只会在两种情况下触发“回”的过程,上述是在最后一层空间是碰到了return,所以给回到它的调用处(阻塞处),因为return会给调用者返回一个值,所以在本层空间,remain接收到了一个值:[[3]];接着执行下面的代码,即是打印remain,所以输出“[[3]]”,执行完print,等于回到了上一层空间,又到了调用处(阻塞处),那么这层空间还有返回值吗?答案是没有,所以“最后一层空间是碰到了return 给它返回的值 只会给最后一层使用”,所以接下来两层都是打印空!
    # 例2:
    def fullpermutation(list):
        if list is None:
            return None
        if len(list) == 1:
            return [list]
        res = []
        pivot = list[0]
        return fullpermutation(list[1:])
    
    
    print(fullpermutation([1, 2, 3]))
    '''
    输出结果为:
    [[3]]
    '''
    
    • 这次是,在最后一层返回时,获得了一个返回值 [[3]] ,然后回到上一层时,前面又有return 表示需要把本层的返回值,返回到上层的接收处,重复,直到回到最外层,这个从底层传上来的返回值,一直传到了最外层,所以才打印出来的,只有最后一层,但是每次一层都获得了返回值,和例子1 后面两层没有返回值是不同的哦!
    # 例3:
    def fullpermutation(list):
        if list is None:
            return None
        if len(list) == 1:
            return [list]
        res = []
        pivot = list[0]
        remain = fullpermutation(list[1:])
        print(list)
    
    
    print(fullpermutation([1, 2, 3]))
    '''
    输出结果为:
    [2, 3]
    [1, 2, 3]
    None
    '''
    
    • 最后一层碰到return,触发会的过程,回到调用处,执行阻塞处下面的代码,打印list,这个list是什么?它就是本层空间 参数的规模(因为代码写的是规模不断变小从[1,2,3]>>>[2,3]>>>[3]),显然,从最后一层回到上一层,此时规模是[2,3],所以打印list 就是[2, 3];接着继续回到上一层,即是最外层,规模是[1,2,3],所以打印[1, 2, 3],最后的None是因为最外层函数,没有返回值,所以才打印出None
    # 例4:
    def fullpermutation(list):
        if list is None:
            return None
        if len(list) == 1:
            return [list]
        res = []
        pivot = list[0]
        remain = fullpermutation(list[1:])
        return list
    
    
    print(fullpermutation([1, 2, 3]))
    '''
    输出结果为:
    [1, 2, 3]
    '''
    
    • 依照上面的步骤,触发回的过程,只要没有到达最外层,return list 返回本层的规模(参数规模),那么这个返回值就会给本层的接收者 remain 不可能给最外层的接收者,虽然这里没有打印 remain的值,但是这里的remain和第一个列子中的remain,后面层数是有返回值的哦(下面例子就会体现),本例,返回到最外层时,list的本层规模为 [1,2,3] 最外层接收者接收到,然后打印出来,所以是[1,2,3]
    # 例5:
    def fullpermutation(list):
        if list is None:
            return None
        if len(list) == 1:
            return [list]
        res = []
        pivot = list[0]
        remain = fullpermutation(list[1:])
        print(remain)
        return list
    
    
    print(fullpermutation([1, 2, 3]))
    '''
    输出结果为:
    [[3]]
    [2, 3]
    [1, 2, 3]
    '''
    
    • 看上面的例子,这次我们是打印了 remain,因为返回的过程中,指向阻塞处(调用处)下面的代码,每次return list 即是 在本层返回 当前的参数规模,所以 remain 是能接收本层的返回值的,所以会打印 [[3]] ,[2, 3] ;最后 [1, 2, 3] 是最外层打印的
    # 例6:
    def fullpermutation(list):
        if list is None:
            return None
        if len(list) == 1:
            return [list]
        res = []
        pivot = list[0]
        remain = fullpermutation(list[1:])
        print(remain)
        print(list)
        return list
    
    
    print(fullpermutation([1, 2, 3]))
    '''
    输出结果为:
    [[3]]
    [2, 3]
    [2, 3]
    [1, 2, 3]
    [1, 2, 3]
    '''
    
    • 这个,就是所有的融合;通过上面的代码我们来总结下return的返回值:最后一层遇到的return 需要执行 回的过程,此时的返回值 值会返回给最后的调用处的接收者;然后执行 阻塞处下面的代码时,如果又遇到return 这里的返回值,如果没有到达最外层,都是给本层的接收者!为什么要大费周章的讲这个,是因为我们在写递归时,往往不清楚return 要怎么写,已及它的返回值是什么?接下来就要看下return 如何解决问题的

    • 请用递归完成一个字符串的反转,输入字符串“abcd”,完成翻转成“dcba”
      除了递归,我们可以直接用字符串的切片来完成,如下,但是这里是要讲递归的思想,不体现方法优劣!

    s="abcd"
    print(s[::-1])
    

    想一下递归的思路该怎么做?
    思路一:按照上面的例子,不断的划分子规模,我们选的是划分原字符串的规模,都是往后截取的,比如第一次参数s=“abcd” 我们取参数s[1:] ,不断调用函数,每次传入参数为:‘bcd’ ‘cd’ ‘d’ ,这样最后一层返回d 我们能拿到最后一个值,然后最后一个返回值d 加上 当前规模的第一个值,就完成了反转,具体代码如下:

    def str_reverse(s):
        if len(s) <= 1: # 递归出口
            return s
        # last = str_reverse(s[1:])
        # return last + s[0]
        return str_reverse(s[1:]) + s[0] # 每次返回最后一层的值,加上当前规模的第一个值
    

    思路二:改变下子规模,我们这次不划分原字符串,而是从它的索引下手,传入最后一个元素的索引,不断去递归索引的值,这时,变的是end的值,从 3 到 2 1 0,到0时触发回的过程,返回当前索引的值,即是 a (不断向前取值),这时我们再加上当前层的s,因为没有划分s所以s每一层都是等于‘abcd’的,我们每次取当前end索引指向的字符串的值,等于从前往后遍历字符串 ‘abcd’ ,两部分链接起来,就完成了反转:每次的返回值为 a, ba , cba, dcba,

    def reve(str, end):
        if end == 0:
            return "" + str[0]
        last = str[end] + reve(str, end - 1)
        return last
    
    
    s = "abcd"
    print(reve(s, len(s) - 1))
    
    • 两种做法都用到return,而是还有重要的递归思路,下面就来看看递归要用什么思路来解

    • 来试下“反转链表”如何用递归做,首先对于一个单链表,要对它反转,我们的思路依旧可以通过不断向后划分子规模,找到它的最后一个结点,然后从后往前依次改变每个结点的指向,让最初的头结点变成尾结点,让它最后指向None;那么具体步骤是:用递归找到最后一个结点,我们可以通过前一个结点的next区域,不断递归,找到下一个结点,直到当前结点的next是None,说明它就是最后一个结点,这也是我们递归的出口,那么依次让它返回,同时改变指向,就完成了,具体看下面的图解:

    class ListNode: 
        def __init__(self, x):
            self.val = x
            self.next = None
    
    
    class Solution:
        def ReverseList(self, pHead):
            if pHead is None: # 判断传入的头结点是否为空
                return None
            if pHead.next is None: # 如果只有一个结点,直接返回结点;同时也是递归的出口
                return pHead
            last_node = self.ReverseList(pHead.next) # last_node永远只接收到了最后一个结点
            pHead.next.next = pHead # 后一个结点,指向前一个结点
            pHead.next = None # 前一个结点,在不同的层,先指向None,如果到达最外层也会指向None
            return last_node # 最后返回最后一个结点,表示反转成功
    
    • 到达最后一层,触发回的过程,返回 last_node 结点给最后第四层,执行阻塞处下面的代码,因为pHead.next.next 是None,它不用改变也行,直接到 return last_node 把 last_node给第三层用…
      在这里插入图片描述
    • 第三层获得 last_node ,执行阻塞处下面的代码,改变指向,pHead.next.next 是“5结点”,它的指针指向 pHead,即是上一个结点,然后上一个结点指向None;因为这里并不需要用一个temp 来保存前一个指针信息,表面上是断开链接,会丢掉数据,其实不会丢掉,因为他们不再同一层;可以用temp先保存前一个结点的数,这属于递归的写,在我的文章>>>反转链表多种解法 有提到,这里不细说!
      在这里插入图片描述
      在这里插入图片描述
    • 直到 回到最外层,起初的头结点,自然会指向None,最后返回 last_node即可
      在这里插入图片描述
    • 这才是 链表反转 递归的详细过程,果然和我开始理解的不一样,当初怎么都无法理解,直到用断点调试,才发现真正的过程,是这样,大家可以用断点调试下,看下代码的具体过程,下面是测试代码:
    class ListNode:
        def __init__(self, x):
            self.val = x
            self.next = None
    
    
    class Solution:
        def ReverseList(self, pHead):
            if pHead is None:
                return None
            if pHead.next is None:
                return pHead
            last_node = self.ReverseList(pHead.next)
            print(last_node.val)
            pHead.next.next = pHead
            pHead.next = None
            return last_node
    
        def print_list(self, node):  # 打印测试
            if node is None:
                return None
            while node:
                print(node.val, end="")
                node = node.next
            print()
    
    
    if __name__ == '__main__':
        n1 = ListNode(1)  # 依次实例5个结点
        n2 = ListNode(2)
        n3 = ListNode(3)
        n4 = ListNode(4)
        n5 = ListNode(5)
        n1.next = n2  # 依次将结点链接起来,形成一个链表
        n2.next = n3
        n3.next = n4
        n4.next = n5
        n5.next = None
    
        obj = Solution()
        print(obj.ReverseList(n1).val)
        # obj.print_list(n1) # 1 2 3 4 5
        # obj.print_list(obj.ReverseList(n1))  # 5 4 3 2 1
    

    递归思路

    • 思想:
      1.找到当前这个值与上一个值的关系
      2.找到程序的出口 有个明确的结束条件
      3.假设当前功能已经完成 每次进入更深一层递归时,问题规模相比上次递归都应有所减少

    • 递归思路:
      (1)找重复:看哪一部分是 实现函数的变化;每次进入更深一层递归时,问题规模相比上次递归都应有所减少
      (2)找变化:变化的量应该作为参数
      (3)找边界(出口):终止条件

    • 递归可以分为:
      (1)直接量+小规模子问题
      (2)多个小规模子问题
      (3) “切蛋糕”思维
      (4)找递推公式,等价交换公式

    二分法和递归

    # 二分法一定是在排序好的数据里使用
    
    lst = [33, 22, 44, 55, 66, 88, 77, 99, 101, 238, 345, 456, 567, 678, 789]
    n = 76
    lst.sort()
    left = 0
    right = len(lst) - 1
    
    while left <= right:  # 条件是 开头<=结尾
        middle = (left + right) // 2
        if lst[middle] > n:  # 每次用对折后,中间的数和 查找对象比较
            right = middle - 1
        elif lst[middle] < n:
            left = middle + 1
        elif lst[middle] == n:
            print("找到了")
            break
    else:
        print("这个数不在列表中")
    
    # 递归函数来做
    lst = [22, 33, 44, 55, 66, 77, 88, 99, 101, 238, 345, 456, 567, 678, 789]
    
    
    def func(n, left, right):
        if left <= right:  # 边界
            mid = (left + right) // 2
            if n > lst[mid]:
                left = mid + 1
                func(n, left, right)  # 递归的入口,目的是再确定一次中间的位置
            elif n < lst[mid]:
                right = mid - 1
                func(n, left, right)
            elif n == lst[mid]:
                print("找到了")
                return  # 递归出口
        else:
            print("没有这个数")
            return  # 递归的出口
    
    
    func(66, 0, len(lst) - 1)
    
    # 升级:如果找到了要求的数,请返回它的索引
    
    lst = [22, 33, 44, 55, 66, 77, 88, 99, 101, 238, 345, 456, 567, 678, 789]
    
    
    def func(n, left, right):
        if left <= right:  # 边界
            mid = (left + right) // 2
            if n > lst[mid]:
                left = mid + 1
                return func(n, left, right)  # 每一层都要返回给上一层的调用者
            elif n < lst[mid]:
                right = mid - 1
                return func(n, left, right)
            elif n == lst[mid]:
                print("找到了")
                return mid  # 多层函数只会将返回值返回给上一层的调用者
        else:
            print("没有这个数")
            return -1
    
    
    print(func(66, 0, len(lst) - 1))
    

    尾递归

    尾递归(自己调用自己,且非表达式:把值放到参数中算)
    

    在这里插入图片描述

    >>>求斐波那契数列第n位是几?(尾递归做法)
    
    def feibo(num, res, temp):
         #使用尾递归法求解斐波那契数量的第num个数字
         if num == 0:
              return res
         else:
              return feibo(num - 1, temp, res + temp)
    
    print(feibo(10,0,1))
    
    # 直接递归  尾递归 与 循环 的对比
    
    import time
    
    
    def Fib_recursion(num):
        '''
        直接使用递归法求解斐波那契数量的第num个数字
        '''
        if num < 2:
            return num
        return Fib_recursion(num - 1) + Fib_recursion(num - 2)
    
    
    def Fib_tail_recursion(num, res, temp):
        '''
        使用尾递归法求解斐波那契数量的第num个数字
        '''
        if num == 0:
            return res
        else:
            return Fib_tail_recursion(num - 1, temp, res + temp)
    
    
    def Fib_circle(num):
        '''
        直接使用循环来求解
        '''
        a = 0
        b = 1
        for i in range(1, num):
            c = a + b
            a = b
            b = c
        return c
    
    
    if __name__ == '__main__':
        num_list = [5, 10, 20, 30, 40, 50]
        for num in num_list:
            start_time = time.time()
            print(Fib_recursion(num))
            end_time = time.time()
            print(Fib_tail_recursion(num, 0, 1))
            end_time2 = time.time()
            print(Fib_circle(num))
            end_time3 = time.time()
            print('正在求解的斐波那契数字下标为%s' % num)
            print('直接递归耗时为 :', end_time - start_time)
            print('尾递归调用耗时为:', end_time2 - end_time)
            print('直接使用循环耗时为:', end_time3 - end_time2)
    

    递归练习题

    >>>打印f-e的数:
    
    def pri(f, e):
        if f > e:
            return
        else:
            print(f)
            return pri(f + 1, e)
    
    
    pri(1, 6)
    
    
    >>>求一个列表的和:
    def sum_lis(li, f):  # 如果单独是传入一个列表,它体现不了变化
        """
        :param li: 传入一个列表
        :param f: 列表起始位置
        :return: 列表和
        """
        if f == len(li) - 1:  # 表示起始位置也是结束位置,即只有一个元素
            return li[f]
    
        return li[f] + sum_lis(li, f + 1)
    
    
    print(sum_lis([1, 2, 3, 4, 5], 0))
    
    # 多引入一个 变化的参数,可以想到第一个元素加上剩下的元素,规模不断变小
    
    # 需求:求 1+2+3+4........100 的和
    num = 1
    count = 0
    while num <= 100:
        count += num
        num += 1
    print(count)
    
    '''
    思路:
    sum(1) + 2 +3.....100
    sum(2) + 3........100
    sum(3) + 4........100
    ...
    sum(98)+99+100
    sum(99) + 100
    sum(100)
    
    sum(100) = sum(99) + 100
    sum(99) = sum(98) + 99
    sum(98) = sum(97) + 98
    .....
    
    sum(2) = sum(1) + 2
    
    sum(1) = 1
    '''
    # 用递归函数解决
    def sum(num):
        if num == 1:  # 出口
            return 1
        return num + sum(num - 1)  # 一直返回sum(num-1)+num,每次递归调用,有return才能有返回值
    
    
    print(sum(100))
    
    >>>需求:打印斐波那契数列
    def fibo(num):  # 参数是表示第n个斐波那契数,函数整体表示获取斐波那契数列中第n个数字的值
        if num == 1 or num == 2:  # 第一个和第二个都是1
            return 1  # 返回1,出口
        return fibo(num - 1) + fibo(num - 2)  # 规律,后一项加上后两项,就等于斐波那契数列第n个数字的值
    
    
    if __name__ == '__main__':
        list_num = []  # 创建一个空列表,开始
        for i in range(1, 21):  # 遍历1-20
            list_num.append(fibo(i))  # 注意这里开始调用函数,获得一个斐波那契数字,将获取到的值填充到list_num
        print(list_num)
    
    
    # 最佳解法:
    def fei_bo(n):
        if n <= 1:
            return (n, 0)
        else:
            (a, b) = fei_bo(n - 1)
            return (a + b, a)
    
    
    print(fei_bo(5))
    # 这里是线性的解法,不再重复计算前一项已知的数
    
    # 求最大公约数
    def maxg(m, n):
        if n == 0:
            return m
        return maxg(n, m % n)
    
    
    print(maxg(6, 0))
    
    # 最大公约数:
    # 如果m%n=0 则n是m的最大公约数;例如4%2=0 则2是最大公约数 
    # 如果m%n=K 则 n%k=?0 >>> f(m,n)=f(n,m%n)
    
    
    >>>用递归实现列表排序:
    def ins(li, k):
        if k == 0:
            return
        # 对前K个元素进行排序
        ins(li, k - 1)
        # 把位置K的元素插入到前面的部分
        x = li[k]
        index = k - 1
        while x < li[index]:
            li[index + 1] = li[index]
            index -= 1
        li[index + 1] = x
        print(li)
    
    
    ins([1, 4, 3, 2], 3)
    
    >>>需求:递归实现遍历目录
    
    import os
    
    
    def get_alldirfile(source_path):  # 定义一个函数获取用户输入的路径名下所有目录和文件
        if not os.path.exists(source_path):  # 判断用户输入的目录是否存在
            return  # 不存在,直接返回,结束该函数,找到一个出口
        list_name = os.listdir(source_path)  # lisdir获取所有目录,并全部放到一个列表中
        for flie_dirname in list_name:  # 遍历下所有的文件目录名
            abs_path = os.path.join(source_path, flie_dirname)  # 拼接成绝对路径
            # 判断下一级是否是目录还是文件,是文件结束,是目录继续深入,直到是文件结束
            if os.path.isfile(abs_path):  # 是文件
                print("file_path:%s" % (abs_path))
            # 也可进行复制操作,open(abs_path,"w",encoding="utf-8")
            if os.path.isdir(abs_path):
                get_alldirfile(abs_path)  # 递归函数
    
    
    if __name__ == '__main__':
        path = r"F:\日语\快乐50音"
        get_alldirfile(path)
    
    # 优化
    import os
    
    
    def file_get(file_path, n):
        list_file = os.listdir(file_path)
        for file in list_file:
            abs_file = os.path.join(file_path, file)
            if os.path.isdir(abs_file):
                print("\t" * n, file)
                file_get(abs_file, n + 1)
            else:
                print("\t" * n, file)
    
    
    file_get("D:\KuGou", 1)
    
    展开全文
  • 参考:一、递归函数两大要素 --终止条件递归方程1、递归方程,即递归调用的方法递归通俗的说就是在函数内部自己调用自己,如何调用就是递归方程。以以下的sum(n)求和函数递归实现方式为例,递归调用方式就是返回n+...

    参考:

    一、递归函数两大要素 --终止条件和递归方程

    1、递归方程,即递归调用的方法

    递归通俗的说就是在函数内部自己调用自己,如何调用就是递归方程。

    以以下的sum(n)求和函数递归实现方式为例,递归调用方式就是返回n+sum(n-1),这样sum(n)的计算方式就类似如下:

    sum(n)=n+sum(n-1) #递归方程,以下为其展开

    sum(n)=n+(n-1)+sum(n-2)

    ...

    sum(n)=n+(n-1)+(n-2)+...+sum(1)

    到这里递归循环就应该结束了,很自然的我们得到了递归循环的结束条件:n=0,此时的返回就不是0+sum(-1)了,直接返回0结束循环即可。

    2、终止条件,即从哪里开始和结束

    从哪里开始和结束要分情况,在上例中有明确的结束条件n=0,n>0则进入递归循环,其隐形的条件就是n不能小于0,因此其开始条件写个n>0即可。

    而其他场景例如遍历B树这种,开始一定是根节点,结束时一定是叶子结点,那么只要开始处理下根节点的打印,之后递归循环子节点即可,因此初始返回值就是根节点相关,之后递归调用以便遍历子节点和后代节点们,终止条件就是找不到子节点。

    二、递归函数示例:

    #!/usr/bin/env python

    def sum(list):

    sum = 0

    # Add every number in the list.

    for i in range(0, len(list)):

    sum = sum + list[i]

    # Return the sum.

    return sum

    print(sum([5,7,3,8,10]))

    #!/usr/bin/env python

    def sum(list):

    if len(list) == 1:

    return list[0]

    else:

    return list[0] + sum(list[1:])

    print(sum([5,7,3,8,10]))

    以上两个函数,第一个使用普通循环方式求和,第二个使用递归循环的方式求和,从效率来讲第一个更好,从逻辑上来讲递归函数更加清晰简洁。

    三、递归的限制条件:

    递归函数使用栈来存储函数调用,过多的递归会导致栈溢出,例如sum([一个超长的序列]),因此平时推荐使用简单循环即可,但是遇到需要进行多层循环或者根本不清楚循环层数的场景,递归就很有用了,只要确定了终止条件和递归方程就可以实现遍历。

    在Python中递归超过1000此就会报出:“RuntimeError: maximum recursion depth exceeded”报错,因此递归也不是无限循环的,这个值也可以修改,你需要大致估算下你的递归次数,然后通过以下方式修改:

    #!/usr/bin/env python

    import sys

    sys.setrecursionlimit(5000)

    #阶乘实现示例:

    def factorial(n):

    if n == 1:

    return 1

    else:

    return n * factorial(n-1)

    print factorial(3000)

    四、递归函数的使用场景:

    一些场景下循环层次数未知,使用递归会非常简便,例如遍历xml文件节点的代码:

    #coding=utf-8

    from xml.dom.minidom import parse

    import sys

    reload(sys)

    sys.setdefaultencoding("utf-8")

    root=parse('').documentElement

    #开始遍历节点

    def iter_xmlNodes(node):

    if node == None:

    return

    if node.nodeType == node.ELEMENT_NODE: #只有ELEMENT_NODE类型的node才有遍历的必要

    print ("ELEMENT Node:%s" %(node))

    for child in node.childNodes:

    iter_xmlNodes(child)

    else:

    print ("Node:%s, NodeType:%d" %(node,node.nodeType))

    #对于前两个if,第一个if表示终止条件,第二个if表示对输入节点的处理,对其子节点执行递归。

    iter_xmlNodes(root)

    展开全文
  • python递归函数什么是递归?递归,就是在函数运行中自己调用自己代码示例:def recursion(n): # 定义递归函数print(n) # 打印nrecursion(n+1) # 在函数的运行种调用递归recursion(1) # 调用函数这个函数在不断的自己...
  • 上文讲了递归算法比较简单的用法,相信对递归算法有一定的概念了。这篇文章再来试试两个相对复杂一点点的案例,最后在总结一下使用递归的一般方法已经需要注意的地方。汉诺塔汉诺塔是一种移动圆盘的游戏,同时也是一...
  • 当一个递归函数的递归层数大于这个值之后程序就会终止并抛出一个异常。这是python为了防止栈溢出而采取的一个防护措施。但是python默认的这个最大递归层数着实有一些保守(大概在1000左),这使得我们无法跑输入...
  • 上期我们介绍了函数式编程,这期内容就是关于递归的函数内容,本期还是按照老规矩,给大家进行核心整理,内容通俗易懂,搭配实际应用,以供大家理解。关于递归:百度解释:是指函数/过程/子程序在运行过程序中直接或...
  • 本文实例讲述了Python递归实现汉诺塔算法。分享给大家供大家参考,具体如下:最近面试题,面试官让我5分钟实现汉诺塔算法(已然忘记汉诺塔是啥)。痛定思痛,回来查了一下汉诺塔的题目和算法。题干与实现如下:A基座...
  • 上期我们介绍了函数式编程,这期内容就是关于递归的函数内容,本期还是按照老规矩,给大家进行核心整理,内容通俗易懂,搭配实际应用,以供大家理解。关于递归:百度解释:是指函数/过程/子程序在运行过程序中直接或...
  • python递归函数

    2019-06-27 00:17:05
    python 递归函数 一、何为递归函数 简单说就是:“函数自己调用自己”。 1 递归函数流程图 2 递归函数实例 # 例如 # 先定义一个函数 def f1(n): ... if n == 1: # 设定终止条件 ret...
  • Python递归

    2019-08-16 15:23:58
    递归(recursion):程序调用自身的编程技巧称为递归。使用递归能够以少量的程序...对于n的一个阶乘,不采用递归(python): def jie_c(n): m=1 for i in range(1,n+1): m=m*i return m print(jie_c(5)) ...
  • 目录:一、递归函数二、闭包的深入讲解三、装饰器的使用一、 递归函数递归函数recursion1.什么是递归函数函数直接或间接的调用自己本身可有解决循环上的问题importtimedefstory():time.sleep(2)print('从前有座山')...
  • ``` class Solution: def canJump(self, nums): if len(nums) == 0: return False def DFS(nums): if len(nums) == 1: return True for i in range(1,nums[0]+1): DFS(nums[i:]) ...
  • Python 递归

    2021-01-12 20:27:57
    基本特例,也称作平凡(一般)情况,它是递归终止的情形。 也就是说在明确函数的目标之后,我们必须寻找出递归的结束条件。问题是如何找这个结束条件?也即,我们需要找出当参数取什么值时递归结束,之后直接把结果...
  • 基本要素基线条件:确定递归到何时终止,函数不再调用自己,也称为递归出口;递归条件:函数调用自己,将大问题分解为类似的小问题,也称为递归体。核心思想每一次递归,整体问题都要比原来减小,并且递归到一定层次...
  • 我们分下面几部分:基础知识递归的写法f(n) = f(n-1) +1递归函数举例倒序输出正整数二叉树的递归查找举例递归习题习题部分有问题的可以在评论区评论。基础知识要理解递归需要的基础知识只有一点:在你调用了一个函数...
  • python递归

    2017-12-06 22:41:00
     (2)使用递归时,需要注意递归的出口,明确递归终止条件。 1 #计算n的阶乘 2 def fun(n): 3 if n==1: 4 return 1 5 else: 6 return fun(n-1)*n 7 print (fun(10)) 3628800 ...
  • python斐波那契递归Good day, learners! In this tutorial we are going to learn about Python Recursion and use it for fibonacci sequence generation. In previous tutorial we discussed about Python ...
  • python递归函数介绍

    2020-09-07 08:46:36
    python递归函数介绍 1、代码 def fibonacci(n): if n == 0: return 0 elif n == 1: return 1 else: return fibonacci(n-1) + fibonacci(n-2) print([fibonacci(x) for x in range(10)]) 2、运行截图 3、补充...
  • 递归函数停止的条件一般定义在递归函数内部,在递归调用前要做一个条件判断,根据判断的结果选择是继续调用自身,还是 return 返回,停止递归递归函数停止的条件: 判断递归的次数是否达到某一限定值 判断运算的...
  • 揭秘Python递归

    2020-06-19 05:17:07
    本教程将介绍递归递归的好处以及如何在Python编程中使用它。 什么是递归递归是一种使用较小问题的解决方案来解决问题的方法。 这种方法可以应用于编程中的许多类型的挑战。 使用递归的好处 使用递归的一些...
  • 例如def f1():print('这是f1')f1() # 直接调用了自己本身def f2():print('这是f2')f3()def f3():print('这是f3')f2() # 间接的调用了自己本身3.python对函数的递归调用循环是有次数的限制的为1000次...
  • 一、解释递归:在调用一个函数的过程中,直接或间接地调用了函数本身这个就叫递归注:Python递归中没有像别的语言对递归进行优化,所以他的每一次调用都会基于上一次的调用进行,并且他设置了最大的递归数量防止...
  • 8 函数基础与递归函数是一系列常被重复使用的语句被抽取成一个"集合体",每次调用这个函数就相当于调用了这些语句,这样总体的代码函数会大幅降低。例1:打印列表各元素值a = list("python")i = 0while i (a):print ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,652
精华内容 7,460
关键字:

python递归终止条件

python 订阅