一、递归函数
函数不仅可以嵌套定义,还可以嵌套调用,即在调用一个函数的过程中,函数内部又调用另一个函数,而函数的递归调用指的是在调用一个函数的过程中又直接或间接地调用该函数本身
本质:递归函数也称为函数的递归
函数在运行时直接或间接的调用了本身
'''直接调用本身'''
def index():
print('hello index') 运行index函数后运行函数体代码
index() 后又开始调用自身,使其反复循环
直至达到Python解释器循环限制
index()
'''
抛出异常:
maximum recursion depth exceeded while calling a Python object
最大的递归深度超出限制了 python解释器自带的应急机制
在有些编程语言中 甚至没有遇警机制 代码会一直执行到计算机崩溃为止
'''
'''间接调用自己'''
def zero():
print('zero')
one()
def one():
print('one')
zero()
zero()
'''
抛出异常:
maximum recursion depth exceeded while calling a Python object
同上一样达到最大递归深度,而这个循环次数Python官方给出的限制次数1000,
用代码可以去验证可能会有些许偏差
'''
'可以验证一下是否有限制'
count = 0 # 定义一个计数器
def index():
print('hello index')
global count # 内部用全局不可变类型的变量,需要用global来声明
count += 1 # 每次循环进来都会加1
print(count) # 每次循环进来都会打印一下count变量值
index() # 调用index()
'''得到count值为996,所以符合综上所述的用代码验证会有些许偏差'''
'''
Python中这个循环次数限制,也可以运用模块来自定义次数
'''
import sys
print(sys.getrecursionlimit()) #获取默认的最大递归深度
sys.setrecursionlimit(2000) 修改至2000次左右(需要放在运行的函数上面,
在此只是演示)
'''
综上得到:
函数的递归不是无限循环的,真正的递归应该是需要满足两个要求
1.每次递归 复杂度必须降低(下一次递归要比上一次递归简单)
2.并且递归函数最终都必须要一个明确的结束条件
真正意义上的应用:
递推:一层层的去寻找答案直至找到答案
回溯:根据最终的答案在向回推导找到答案
'''
'''
用一个小案例来试试:
已知有一个列表,但是我们只需要列表里面的每一个数字,不想要中括号哪些。
'''
ll = [1,[2,[3,[4,[5,[6,[7,[8,[9,[10]]]]]]]]]]
def dig(ll):
for i in ll: 自带结束条件,并且每次传入的数据比上一次简单
if type(i) is int: 判断当前对象是否是数字类型
print(i,end=' ') 是就打印该数字
else:
return dig(i) 不是则继续循环打印剩余的列表
dig(ll) # 1 2 3 4 5 6 7 8 9 10
二、算法之二分法
什么是算法?
算法就是解决问题的有效方法,不是所有的算法都很高效,也有不合格的算法
算法应用场景
几乎涵盖了我们日常生活中的方方面面。如:
推荐算法:(抖音视频推送,淘宝商品推送等)
成像算法:(AI相关等)
'''算法之二分法'''
二分法是算法里面最入门的一个
'''二分法使用要求:待查找的数据集必须有先后顺序(升序、降序)'''
'''
二分法的原理:
获取数据集中间的元素,对比大小
如果获取的中间元素大于目标数据 则保留数据集的左边一半
如果获取的中间元素小于目标数据 则保留数据集的右边一半
然后针对剩下的数据集再次二分
如果获取的中间元素大于目标数据 则保留数据集的左边一半
如果获取的中间元素小于目标数据 则保留数据集的右边一半
'''
ll = [12,2,3,4,45,56,5,345,6,346,35,34,43,23,432]
# 查找一个数346
# 1.排序
ll.sort()
# print(ll)
# print(len(ll))
# 2.去列表寻找中间值,然后拿来和346比较
def demo(ll,demo_num):
if len(ll) == 0:
print('sorry 该数据集中不存在此数据')
return
# 3.获取中间元素的索引值(只能是整数,所有用取整)
middle_index = len(ll) // 2 # 向下取整 15//2 = 7
# 4.判断中间索引对应的数据与目标数据的大小
if demo_num > ll[middle_index]:
# 5.保留右侧数据集
ll_right = ll[middle_index + 1:] # 切分得到右侧部分
# 5.1.后继续对右侧部分进行二分,重复执行相同代码
print(ll_right)
demo(ll_right,demo_num)
elif demo_num < ll[middle_index]:
# 6.保留左侧数据集
ll_left = ll[:middle_index] # 切分得到左侧部分
# 6.1.后继续对左侧部分进行二分,重复执行相同代码
print(ll_left)
demo(ll_left,demo_num)
else:
print('找到了',demo_num)
demo(ll,346)
'''
二分法的缺陷:
1.如果要找的元素就在数据集的开头 二分更加复杂
2.数据集必须有顺序
目前没有最完美的算法 都有相应的限制条件
常见算法的原理及伪代码
二分法、冒泡、快拍、插入、堆排等
'''
三、三元表达式
什么是三元表本质?
是对简单的代码进行缩写 简单的来说就是偷懒的写法减少代码行数
三元表达式只适合较为简洁的条件判定 较为复杂的判定建议不要用这种方式写代码
因为比较让人难以理解
'''三元表达式的语法结构'''
'''
真时的结果 if 判定条件 else 为假时的结果
如果if后面的条件成立 则使用if前面真时的值
如果if后面的条件不成立 则使用else假的值
当结果是二选一的情况下,使用三元表达式较为简便
但是不推荐多个三元表达式嵌套
'''
'例子:获取用户输入的用户名,如果是chen打印welcome chen 否则打印sorry'
正常方式:
name = input('name>>>>:').strip()
if name == 'chen':
print('welcome chen')
else:
print('sorry')
三元表达式:
print('welcome chen') if name == 'chen' else print('sorry')
'''
正常方式五行的代码 三元表达式两行就解决了
在Python中代码不是精简的越少越好 在精简的过程中还要保证代码的可读性
'''
四、生成式
'列表生成式'
给下面列表中的所有的数据值加上'_perfect'
'''正常方式'''
vl = ['a','b','c','d','e']
vls = []
for i in vl:
res = '%s_perfect' % i
vls.append(res)
print(vls)
'''列表生成式'''
vls = [i+'_perfect' for i in vl]
print(vls)
'''提升一下难度,不让列表中的c添加'''
'''正常方式'''
vls = []
for i in vl:
if i == 'c':
vls.append(i)
continue
else:
res = '%s_perfect' % i
vls.append(res)
print(vls)
'''列表生成式'''
vls = [i+'_perfect' for i in vl if i !='c']
这种情况后面不能在写else了,因为for也有for+else语法,所以只能给if+else放在for前面
vls = [i+'_perfect' if i != 'c' else i for i in vl]
print(vls)
'字典生成式'
l1 = ['name','age','gender']
l2 = ['chen',18,'male']
'''正常方式'''
name_dict = {}
for i in range(len(l1)):
name_dict[l1[i]] = l2[i]
print(name_dict)
"""
补充一个方法:enumerate
1. 循环enumerate方法可以得到两个值
索引、元素
"""
'''正常方式'''
for i , j in enumerate(l1):
print(i,j)
'''字典生成式'''
d = {l1[i]: l2[i] for i, j in enumerate(l1)}
print(d)
'集合生成式'
new_set = {i for i in 'hello world'}
print(new_set)