1、算法

英文名:algorithm,就是计算的方法。
# 是截止到目前,人类发现的针对特定场景的,最优的计算方法。是人类智慧的结晶。
# 人脑是复杂的,电脑其实很简单。比如: 999 * 123 人类会将其变为: 1000 * 123 - 123 这样就好算多了,可是电脑不会如此,只会硬算!
学习算法的目的
# 我们学习的算法 都是过去时
# 了解基础的算法 才能创造出更好的算法
# 不是所有的事情都能套用现成的方法解决的
# 有些时候会用到学过的算法知识来解决新的问题

2、递归

1)、楔子

有如下例子:
从前有座山,山上有个庙;庙里有两个和尚,一个老和尚跟一个小和尚。一天,老和尚跟小和尚讲故事:
"从前有座山,山上有个庙;庙里有两个和尚,一个老和尚跟一个小和尚。一天,老和尚跟小和尚讲故事:
'从前有座山,山上有个庙;庙里有两个和尚,一个老和尚跟一个小和尚。一天,老和尚跟小和尚讲故事:
.............................
# 看到这个例子,有何感想?这不是车轱辘话码,自己说自己!
# 这就对了,我们就正式引入递归!
2)、递归函数的定义
在函数中,自己调用自己的函数,叫递归函数。
 depth = 0
def temple_story():
global depth
print('从前有座山,山上有个庙;庙里有两个和尚,一个老和尚跟一个小和尚。一天,老和尚跟小和尚讲故事:')
depth += 1
print(depth)
temple_story() #temple_story() #会报告超过最大递归深度的错误!
# 报错:RecursionError: maximum recursion depth exceeded while calling a Python object # 我们来看看这个深度是多少?添加计数,发现是997次!
# 这个最大递归次数是python定义的,可以改,但建议如此做,因为递归如此多,还解决不了,就说明不适合用递归解决!
import sys
print("最大递归深度是:", sys.getrecursionlimit()) #
sys.setrecursionlimit(50000) #temple_story() # 没有报告错误!执行到3806次就没打印了(并且退出了函数),说明有东西限制了继续递归!
3)、递归的小结
# 如果递归次数太多,就不适合使用递归来解决问题
# 递归的缺点 : 占内存
# 递归的优点: 会让代码变简单
4)、应用场景1:询问年龄
 '''
# alex 多大 n = 1 age(1) = age(2)+2 = age(n+1) + 2
# alex比egon大两岁
# egon多大? n = 2 age(2) = age(3) + 2 = age(n+1) +2
# egon比tom大两岁
# tom多大 n = 3 age(3) = age(4) + 2 = age(n+1) +2
# tom比king大两岁
# king多大?
# king40了 n = 4 age(4) = 40
'''
def ask_age(n):
'''
问年龄,
:param n:被询问的序号
:return: age
'''
if n == 4:
return 40
elif 0 < n < 4:
return ask_age(n + 1) + 2
print('I am ', ask_age(3)) # # 教你看递归 递的是n,归的是return的值
# def ask_age(1):
# if 1 == 4:
# return 40
# elif 1 > 0 and 1 < 4:
# return 46
#
# def ask_age(2):
# if 2 == 4:
# return 40
# elif 2 >0 and 2 < 4:
# age(3) + 2 None +2
#
# def ask_age(3):
# if 3 == 4:
# return 40
# elif 3 >0 and 3 < 4:
#
#
# def ask_age(4):
# if 4 == 4:
# return 40
# elif n >0 and n < 4:
# age(n+1) + 2

3、二分法 (dichotomy),必须处理有序的列表

 #   使用实例:使用二分法查找数列中有没有66,并返回其索引。
num_li = [2,3,5,10,15,16,18,22,26,30,32,35,41,42,43,55,56,66,67,69,72,76,82,83,88] # 没接触二分法之前,我们大概会用for循环遍历数列,判断其中元素是否是66,如果是返回其索引!
# 但是,想一想,如果此数列有几百万个元素,这样遍历会很慢,如何查找最快?答案是:二分法
# 第一次,找到数列最中间的元素,比较它和66的大小,如果大于66,就说明66在它前面,前面的数又组成一个数列num_li_new_1,
# 如果它比66小,则说明66在它的后面,将其后面的数,组成一个新的数列:num_li_new_2
# 第二次,在num_li_new_1或者num_li_new_2中,继续按照第一的方法寻找下去。。。。。。
# 第n次,如果有该元素,一定会找到它,而且只有一个元素了! #1)、第一次尝试用二分法
def find_num(list, target):
mid_index = len(list)//2
if list[mid_index] == target:
print('Congratunation! You get it!')
return mid_index
elif list[mid_index] > target:
new_list = list[:mid_index]
find_num(new_list, target)
else:
new_list = list[mid_index + 1:]
find_num(new_list, target) res = find_num(num_li, 67)
print(res) # 惊奇的发现,打印的结果是:None
# 分析未得到预想结果的原因: todo:没有接收返回值,也没有返回任何值! 所以为None
def find_num(list, target): # 第一步:list=num_li target = 67
mid_index = len(list) // 2 # 第二步:mid_index = 24//2 = 12
if list[mid_index] == target: # list[mid_index] = list[12] = 41
print('Congratunation! You get it!')
return mid_index
elif list[ mid_index ] > target:
new_list = list[ :mid_index ]
find_num(new_list, target)
else: #第三步:41 < 67
new_list = list[ mid_index + 1: ] # 第四步:new_list = list[13:] = [42,43,55,56,66,67,69,72,76,82,83,88]
find_num(new_list, target) # 第五步:find_num(new_list, 67)todo:没有接收返回值,也没有返回任何值! def find_num(list, target): # 第六步:list=new_list target = 67
mid_index = len(list) // 2 # 第七步:mid_index = 12//2 = 6
if list[mid_index] == target: # list[mid_index] = list[6] = 69
print('Congratunation! You get it!')
return mid_index
elif list[ mid_index ] > target: # 第八步:69 > 67
new_list = list[ :mid_index ] # 第九步:new_list = list[:6] = [42,43,55,56,66,67]
find_num(new_list, target) # 第十步:find_num(new_list, 67) todo:没有接收返回值,也没有返回任何值!
else:
new_list = list[ mid_index + 1: ] #
find_num(new_list, target) # def find_num(list, target): # 第十一步:list=new_list target = 67
mid_index = len(list) // 2 # 第十二步:mid_index = 6//2 = 3
if list[mid_index] == target: # list[mid_index] = list[3] = 56
print('Congratunation! You get it!')
return mid_index
elif list[ mid_index ] > target: #
new_list = list[ :mid_index ]
find_num(new_list, target) # 第十步:find_num(new_list, 67)
else: # 第十三步:56 < 67
new_list = list[mid_index + 1:] # 第十四步:new_list = list[4:] = [66,67]
find_num(new_list, target) # 第十五步: find_num(new_list, 67) todo:没有接收返回值,也没有返回任何值! def find_num(list, target): # 第十六步: list=new_list target = 67
mid_index = len(list)//2 # 第十七步:mid_index = 2//2 = 1
if list[mid_index] == target: # 第十八步:list[mid_index] = list[1] = 67 正好相等!
print('Congratunation! You get it!') # 第十九步:输出Congratunation! You get it!
return mid_index # 第二十步:将mid_index = 1 todo 返回给调用该函数的地方:即第十五步
elif list[mid_index] > target:
new_list = list[:mid_index]
find_num(new_list, target)
else:
new_list = list[mid_index + 1:]
find_num(new_list, target) #2)、第二次尝试用二分法 def find_num(list, target):
mid_index = len(list)//2
if list[mid_index] == target:
print('Congratunation! You get it!')
return mid_index
elif list[mid_index] > target:
new_list = list[:mid_index]
return find_num(new_list, target)
else:
new_list = list[mid_index + 1:]
return find_num(new_list, target) res = find_num(num_li, 67)
print(res) # 继续惊奇的发现,结果是:0,这并不是我们预想的结果!
# 原因分析:索引乱了,我们切分数列后,用的是新的索引! # 3)、第三次尝试用二分法 #def find_num(list, target, start = 0, end = len(list)): #TypeError: object of type 'type' has no len()
def find_num(list, target, start = 0, end = None):
end = len(list) if end is None else end
# mid_index = len(list)//2 # 有时会报错:IndexError: list index out of range
mid_index = (end - start)//2 + start #
if list[mid_index] < target:
#new_list = list[ mid_index + 1:end ] # 加start和end后,不用传了,否者列表会越界!
return find_num(list, target, start=mid_index + 1, end=end)
elif list[mid_index] > target:
#new_list = list[start:mid_index]
return find_num(list, target, start=start, end=mid_index)
else:
print('Congratunation! You get it!')
return mid_index res = find_num(num_li, 66)
print(res) # 结果是出现了,还发现一个问题,如果查找的数不在列表中,会报错:RecursionError: maximum recursion depth exceeded in comparison # 4、第四次
def find_num(list, target, start = 0, end = None):
end = len(list) if end is None else end
if end > start:
mid_index = (end - start)//2 + start #
if list[mid_index] < target:
return find_num(list, target, start=mid_index + 1, end=end)
elif list[mid_index] > target:
return find_num(list, target, start=start, end=mid_index)
else:
print('Congratunation! You get it!')
return mid_index
else:
return '该数列中没有你找的数!' res = find_num(num_li, 44)
print(res)

Python进阶-Ⅸ 递归 二分法的更多相关文章

  1. python --- 14 递归 二分法查找

    一.递归 1.函数自己调用自己 2.官方说明最大深度1000,但跑不到1000,要看解释器, 实测998 3.使⽤递归来遍历各种树形结构 二.    二分法查找 掐头结尾取中间 ,  必须是有序序列 ...

  2. 【学习笔记】--- 老男孩学Python,day15 python内置函数大全,递归,二分法

    1. lamda匿匿名函数2. sorted()3. filter()4. map()5. 递归函数 一. lamda 匿名函数 为了了解决一些简单的需求⽽设计的⼀句话函数 语法: 函数名 = lam ...

  3. python之内置函数(lambda,sorted,filter,map),递归,二分法

    一.lambda匿名函数 为了解决一些简单需求而设计的一句话函数,lambda表示的是匿名函数,不需要用def来声明,一句话就可以声明出一个函数. 语法: 函数名 = lambda 参数 : 返回值 ...

  4. Python匿名函数/排序函数/过滤函数/映射函数/递归/二分法

    一. lamda匿名函数 为了解决一些简单的需求而设计的一句话函数 # 计算n的n次方 def func(n): return n**n print(func(10)) f = lambda n: n ...

  5. Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量

    Python进阶----线程基础,开启线程的方式(类和函数),线程VS进程,线程的方法,守护线程,详解互斥锁,递归锁,信号量 一丶线程的理论知识 什么是线程:    1.线程是一堆指令,是操作系统调度 ...

  6. Python进阶(七)----带参数的装饰器,多个装饰器修饰同一个函数和递归简单案例(斐波那契数列)

    Python进阶(七)----带参数的装饰器,多个装饰器修饰同一个函数和递归简单案例(斐波那契数列) 一丶带参数的装饰器 def wrapper_out(pt): def wrapper(func): ...

  7. Python进阶5---StringIO和BytesIO、路径操作、OS模块、shutil模块

    StringIO StringIO操作 BytesIO BytesIO操作 file-like对象 路径操作 路径操作模块 3.4版本之前:os.path模块 3.4版本开始 建议使用pathlib模 ...

  8. python进阶06 常用问题库(2)datetime模块 base64

    python进阶06 常用问题库(2)datetime模块 base64 一.datetime模块(时间) 1.datetime.time() t=datetime.time(20,43,30,1) ...

  9. python进阶强化学习

    最近学习了慕课的python进阶强化训练,将学习的内容记录到这里,同时也增加了很多相关知识. 主要分为以下九个模块: 基本使用 迭代器和生成器 字符串 文件IO操作 自定义类和类的继承 函数装饰器和类 ...

随机推荐

  1. 常见算法合集[java源码+持续更新中...]

    一.引子 本文搜集从各种资源上搜集高频面试算法,慢慢填充...每个算法都亲测可运行,原理有注释.Talk is cheap,show me the code! 走你~ 二.常见算法 2.1 判断单向链 ...

  2. 【新特性速递】CSS3动画增强

    FineUIPro/Mvc/Core的下个版本(v6.1.0),我们对多个地方的CSS3动画进行了增强,使得用户体验更好. 1. 树控件启用EnableSingleExpand时,使得展开动画和折叠其 ...

  3. VBA基础 - 函数和模块

    概要 对于一般的 VBA 程序来说, 可能一个或几个函数就行了. 毕竟, VBA 只是作为 excel 的辅助工具来用的. 但是, 随着 VBA 写的越来越多, 用个工程来管理就有必要了, 而一个代码 ...

  4. docker 通过中间镜像加速部署

    概要 实施 修改前的实施时间 制作编译用的镜像 测试修改后的实施时间 概要 使用 docker 打包镜像的时候, 每次耗费时间最多的就是 docker build 的过程. 特别是对于前端工程的打包, ...

  5. 动手学深度学习10- pytorch多层感知机从零实现

    多层感知机 定义模型的参数 定义激活函数 定义模型 定义损失函数 训练模型 小结 多层感知机 import torch import numpy as np import sys sys.path.a ...

  6. javascript播放图片序列帧

    javascript播放图片序列帧1 先预加载<pre>var load_img = [];for(k=0;k<=16;k++){load_img.push( '/cjsxy/ima ...

  7. @Resource和@Autowire用谁?

    我选了@Resource 1.当注入的属性是接口 1.1在接口只有一个实现类的时候,@Resource和@Autowire 在功能上是没有区别的 1.2如果接口有多个实现类,在写法上,@Autowir ...

  8. 【Oracle】RMAN duplicate复制库

    基础环境: 172.17.4.60 操作系统:Linux 6.4 数据库:Oracle11gR2 (源数据库) 172.17.4.61 操作系统:Linux 6.4 数据库:Oracle11gR2 ( ...

  9. jquery实现移动端页面加载后,向上滚动指定距离无效引起的探索

    效果如下,页面加载完后向上滚动一段距离 最近一同事询问用jquery为何无法实现上面效果,查看代码后发现代码并没写错,   也正确引入了zepto.js,也不是版本问题(因为是移动端项目,出于性能和需 ...

  10. Quartz.net任务调度

    一.Quartz.net简介 Quartz.net是一个开源的任务调度框架,很多定时任务.调度任务都可以用这个框架,如定时日志等. 二.Quartz.net用途 定时给女朋友发送消息 女朋友生日的时候 ...