洗礼灵魂,修炼python(26)--编程核心之“递归”
递归
1.什么是递归:
其实前面都提过,但没有详细讲。多次调用自身就叫递归
看图,这种就叫递归
看过盗梦空间没?其实也是递归
2.递归需要满足条件:
- 有调用函数自身
- 有一个正确的返回条件来结束
- 在使用递归策略时,必须有一个明确的递归结束条件,即递归出口
3.递归和迭代的区别:
- 递归:(recursion)指的是一个函数不断调用自身的行为,比如以编程方式输出著名的斐波纳契数列
- 遍历:(traversal)指的是按照一定的规则访问树形结构的每一个节点,而且每个节点都只访问一次
4.递归的深度在python3版本上默认设置100层,作为保护设置
因为如果一直无限递归的结果就和无线循环一样,直到计算机崩溃才结束
修改递归深度(前面在sys模块提到过):
>>> import sys >>> sys.setrecursionlimit (100000) #括号内的参数即为递归深度
5.递归实际运用:
例1:求一个数的阶乘
1)使用while:
# -×- coding:utf-8 -*-a=int(input("请输入一个正整数:")) s=1 while a-1!=-1: s=s*a a=a-1 if a<0: break print(s)
结果:
>>> 请输入一个正整数:7 5040
2)使用函数:
# -×- coding:utf-8 -*-
def M(a): s=a for i in range(1,a): s*=i return s
a=int(input("请输入一个正整数:")) s=M(a) print("数字 %d 的阶乘为:%d"%(a,s))
结果:
请输入一个正整数:8
数字 8 的阶乘为:40320
3)当然也可以函数+while方法:
# -×- coding:utf-8 -*-def M(a): s=1 while a-1!=-1: s=s*a a=a-1 return s a=int(input("请输入一个正整数:")) s=M(a) print("数字 %d 的阶乘为:%d"%(a,s))
效果是一样的,就不再输出了
5)使用for循环:
# -×- coding:utf-8 -*-def f(n): result=n for i in range(1,n): result*=i return result
结果:
>>> temp=f(8) >>> temp 40320
6)使用递归:
# -×- coding:utf-8 -*-
def M(a): if a==1: return 1 else: return a*M(a-1)
结果:
>>> temp=M(8) >>> temp 40320
使用了这么多方法,你有没有感觉,其实使用递归,思路上是最简单的,当然不去考虑代码量的问题。递归的优势就是分治思想,分治思想就是把一个大问题分成很多个相同解决方法的小问题,当把解决的一个小问题利用程序重复进行多次直到把这个大问题解决掉。
例2:利用斐波纳契数列打印在给定周期内生出的兔崽子数
1)使用迭代:
# -×- coding:utf-8 -*-def tuzi(n): n1=1 n2=1 n3=1 #此为初始值 if n<1: print("输入有误!") return "Error" while (n-2)>0: n3=n2+n1 n1=n2 n2=n3 n-=1 return n3 n=int(input("请输入周期数:")) result=tuzi(n) if result!="Error": print("总共有%d只兔子"%result)
结果:
>>> result=tuzi(8) >>> result 21
2)使用函数,列表结合实现:
3)使用递归:
def tuzi(n): if n<1: print("输入有误:") return "Error" if n==1 or n==2: return 1 else: return tuzi(n-1)+tuzi(n-2) n=int(input("请输入经过的月份数:")) result=tuzi(n) if result!="Error": print("总共有%d只兔崽子"%result) print("结束!")
结果:
>>> result=tuzi(8) >>> result 21
看完这么多,我想你应该对递归有所了解了,是的,迭代比递归快很多,迭代因为只是遍历对象内的所有参数,而递归是每次都会调用自身,每次都会处理一次属于自己的那一段代码块,所以递归更慢,但是思路确实很清晰,并且使用递归函数时需要注意防止栈溢出
好的,最后一例,如果你会了,那么递归你就已经掌握了:
例3:使用递归求解汉诺塔
了解:什么是汉诺塔?
法国数学家爱德华·卢卡斯曾编写过一个印度的古老传说:在世界中心贝拿勒斯(在印度北部)的圣庙里,一块黄铜板上插着三根宝石柱(或者石针)。印度教的主神梵天在创造世界的时候,在其中一根针上从下到上地穿好了由大到小的64片圆盘,这就是所谓的汉诺塔。不论白天黑夜,总有一个僧侣在按照下面的法则移动这些圆盘:一次只移动一个圆盘,不管在哪根针上,小圆盘必须在大圆盘上面。僧侣们预言,当所有的圆盘都从梵天穿好的那根针上移到另外一根针上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽
比如三个罗盘三根柱子时:
我要把x柱上的圆盘转移到Z柱上,但是每次只能移动一个圆盘,思路是: 把小圆盘和中圆盘从X放到Y上,再把大圆盘放到Z上,再把小圆盘和中圆盘放到Z上就行对吧?
但实践起来就不止简简单单的一两句话的:
步骤:
1.把小圆盘和中圆盘借用Z移到Y上
- 1):把小圆盘放到Z上
- 2):把中圆盘放到Y上
- 3):把小圆盘放到Y上
2.把大圆盘移到X上
通过这大的两步就把三个圆盘从x移到z上了。而第一步时又可以分为一个同类型的小问题,把其当作是两个圆盘时移动操作,而一个圆盘时就直接就移动过去。这就是递归最好的体现。但其实三个圆盘是很简单的,如果不止三个圆盘呢?如果就如上面所说有64个圆盘呢?所以这就需要程序解决了
参考答案:(在看答案前,我希望你已经努力做过)
# -*- coding:utf-8 -*- def hanoi(n,x='x',y='y',z='z'): if n==1: print(x, "-->" ,z) else: hanoi(n-1,x,z,y) #将前n-1个盘子从x移动到y上 print(x, "-->" ,z)#将最底下的最后个盘子从x移动到z上 hanoi(n-1,y,x,z) #将y上的n-1个盘子移动到z上 n=int(input("请输入汉诺塔的层数:")) hanoi(n)
hanoi
>>> hanoi(5,'x','y','z') x --> z x --> y z --> y x --> z y --> x y --> z x --> z x --> y z --> y z --> x y --> x z --> y x --> z x --> y z --> y x --> z y --> x y --> z x --> z y --> x z --> y z --> x y --> x y --> z x --> z x --> y z --> y x --> z y --> x y --> z x --> z
结果
其实这个汉诺塔很简单,方法也很多,自己下去测试就懂了
这就是递归,在编程语言里很重要的一个概念
洗礼灵魂,修炼python(26)--编程核心之“递归”的更多相关文章
- Python面向对象编程核心思想
原文地址https://blog.csdn.net/weixin_42134789/article/details/80194788 https://blog.csdn.net/happyjxt/ar ...
- 洗礼灵魂,修炼python(69)--爬虫篇—番外篇之feedparser模块
feedparser模块 1.简介 feedparser是一个Python的Feed解析库,可以处理RSS ,CDF,Atom .使用它我们可从任何 RSS 或 Atom 订阅源得到标题.链接和文章的 ...
- 洗礼灵魂,修炼python(85)-- 知识拾遗篇 —— 深度剖析让人幽怨的编码
编码 这篇博文的主题是,编码问题,老生常谈的问题了对吧?从我这一套的文章来看,前面已经提到好多次编码问题了,的确这个确实很重要,这可是难道了很多能人异士的,当你以为你学懂了,在研究爬虫时你发现你错了, ...
- 洗礼灵魂,修炼python(7)--元组,集合,不可变集合
前面已经把列表的基本用法讲解完 接着讲python的几大核心之--元组(tuple) 1.什么是元组? 类似列表,但为不可变对象,之前提到列表是可变对象,所谓可变对象就是支持原处修改,并且在修改前后对 ...
- Python编程核心之makeTextFile.py和readTextFile.py
引言: 最近大半年都在学习python编程,在双十一的时候购买了<Python编程核心>,看到makeTextFile.py和readTextFile.py两个例子有点错误,所以在这里给修 ...
- Python 编程核心知识体系(REF)
Python 编程核心知识体系: https://woaielf.github.io/2017/06/13/python3-all/ https://woaielf.github.io/page2/
- Python 网络编程(二)
Python 网络编程 上一篇博客介绍了socket的基本概念以及实现了简单的TCP和UDP的客户端.服务器程序,本篇博客主要对socket编程进行更深入的讲解 一.简化版ssh实现 这是一个极其简单 ...
- python高级编程:有用的设计模式1
# -*- coding: utf-8 -*-__author__ = 'Administrator'#python高级编程:有用的设计模式#设计械是可复用的,某种程序上它对软件设计中觉问题提供的语言 ...
- python网络编程-01
python网络编程 1.socket模块介绍 ①在网络编程中的一个基本组件就是套接字(socket),socket是两个程序之间的“信息通道”. ②套接字包括两个部分:服务器套接字.客户机套接字 ③ ...
随机推荐
- MySQL Workbench导出Model提示['ERROR 1064 (42000): You have an error in your SQL syntax....syntax to use near 'VISIBLE']
CREATE TABLE IF NOT EXISTS `pihealth`.`warning_events` ( `wid` INT NOT NULL AUTO_INCREMENT, `wtime` ...
- 04-TypeScript中的方法新功能(上)
在TypeScript中,提供了一些函数的新功能,能够简化JavaScript中的一些比较复杂代码才能实现的一些能力. 在C#后端语言中,能够对方法传递的参数指定params关键字,也就是可以传递任意 ...
- IMSI
国际移动用户识别码(IMSI:International Mobile Subscriber Identification Number)是区别移动用户的标志,储存在SIM卡中,可用于区别移动用户的有 ...
- Atom相关资料整理
官网地址 https://atom.io/ Atom 中文社区 https://atom-china.org/ 常用插件 Emmet 这款插件是用来支持zend-coding,Emmet的前身是大名鼎 ...
- dva reduxRouter 跳转路由的参数
应该由 新页面的 this.props.location获取
- Python 虚拟环境 | Mac/Linux下如何避坑安装配置Virtualenv
1.为什么要使用虚拟环境 在Python中,不同的应用可能需要用到不同版本的第三方包,而这些第三方包被统一存放到目录site-packages中,不同版本的包容易相互覆盖,如安装Django 2.1时 ...
- linux下configure,make,make install的意义
tar.gz.tar.bz2的是源代码包,需要编译之后才能安装,在编译过程中你可以指定各种参数以适应你的系统需求,比如安装位置,优化参数,要哪些功能不要哪些功能等等.这类源代码包需要解压后(tar.g ...
- Java并发编程笔记之LinkedBlockingQueue源码探究
JDK 中基于链表的阻塞队列 LinkedBlockingQueue 原理剖析,LinkedBlockingQueue 内部是如何使用两个独占锁 ReentrantLock 以及对应的条件变量保证多线 ...
- Mysql 5.7 基于组复制(MySQL Group Replication) - 运维小结
之前介绍了Mysq主从同步的异步复制(默认模式).半同步复制.基于GTID复制.基于组提交和并行复制 (解决同步延迟),下面简单说下Mysql基于组复制(MySQL Group Replication ...
- 如何做自己的服务监控?spring boot 2.x服务监控揭秘
Actuator是spring boot项目中非常强大一个功能,有助于对应用程序进行监视和管理,通过 restful api请求来监管.审计.收集应用的运行情况,针对微服务而言它是必不可少的一个环节. ...