1、算法
英文名:algorithm,就是计算的方法。
# 是截止到目前,人类发现的针对特定场景的,最优的计算方法。是人类智慧的结晶。
# 人脑是复杂的,电脑其实很简单。比如:
999 * 123 人类会将其变为: 1000 * 123 - 123 这样就好算多了,可是电脑不会如此,只会硬算!
学习算法的目的
# 我们学习的算法 都是过去时
# 了解基础的算法 才能创造出更好的算法
# 不是所有的事情都能套用现成的方法解决的
# 有些时候会用到学过的算法知识来解决新的问题
2、递归
1)、楔子
有如下例子:
从前有座山,山上有个庙;庙里有两个和尚,一个老和尚跟一个小和尚。一天,老和尚跟小和尚讲故事:
"从前有座山,山上有个庙;庙里有两个和尚,一个老和尚跟一个小和尚。一天,老和尚跟小和尚讲故事:
'从前有座山,山上有个庙;庙里有两个和尚,一个老和尚跟一个小和尚。一天,老和尚跟小和尚讲故事:
.............................
# 看到这个例子,有何感想?这不是车轱辘话码,自己说自己!
# 这就对了,我们就正式引入递归!
2)、递归函数的定义
在函数中,自己调用自己的函数,叫递归函数。
1 depth = 0 2 def temple_story(): 3 global depth 4 print('从前有座山,山上有个庙;庙里有两个和尚,一个老和尚跟一个小和尚。一天,老和尚跟小和尚讲故事:') 5 depth += 1 6 print(depth) 7 temple_story() 8 9 #temple_story() #会报告超过最大递归深度的错误! 10 # 报错:RecursionError: maximum recursion depth exceeded while calling a Python object 11 12 # 我们来看看这个深度是多少?添加计数,发现是997次! 13 # 这个最大递归次数是python定义的,可以改,但建议如此做,因为递归如此多,还解决不了,就说明不适合用递归解决! 14 import sys 15 print("最大递归深度是:", sys.getrecursionlimit()) # 1000 16 sys.setrecursionlimit(50000) 17 18 #temple_story() # 没有报告错误!执行到3806次就没打印了(并且退出了函数),说明有东西限制了继续递归!
3)、递归的小结
# 如果递归次数太多,就不适合使用递归来解决问题
# 递归的缺点 : 占内存
# 递归的优点: 会让代码变简单
4)、应用场景1:询问年龄
1 ''' 2 # alex 多大 n = 1 age(1) = age(2)+2 = age(n+1) + 2 3 # alex比egon大两岁 4 # egon多大? n = 2 age(2) = age(3) + 2 = age(n+1) +2 5 # egon比tom大两岁 6 # tom多大 n = 3 age(3) = age(4) + 2 = age(n+1) +2 7 # tom比king大两岁 8 # king多大? 9 # king40了 n = 4 age(4) = 40 10 ''' 11 def ask_age(n): 12 ''' 13 问年龄, 14 :param n:被询问的序号 15 :return: age 16 ''' 17 if n == 4: 18 return 40 19 elif 0 < n < 4: 20 return ask_age(n + 1) + 2 21 print('I am ', ask_age(3)) 22 23 # # 教你看递归 递的是n,归的是return的值 24 # def ask_age(1): 25 # if 1 == 4: 26 # return 40 27 # elif 1 > 0 and 1 < 4: 28 # return 46 29 # 30 # def ask_age(2): 31 # if 2 == 4: 32 # return 40 33 # elif 2 >0 and 2 < 4: 34 # age(3) + 2 None +2 35 # 36 # def ask_age(3): 37 # if 3 == 4: 38 # return 40 39 # elif 3 >0 and 3 < 4: 40 # 42 41 # 42 # def ask_age(4): 43 # if 4 == 4: 44 # return 40 45 # elif n >0 and n < 4: 46 # age(n+1) + 2
3、二分法 (dichotomy),必须处理有序的列表
1 # 使用实例:使用二分法查找数列中有没有66,并返回其索引。 2 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] 3 4 # 没接触二分法之前,我们大概会用for循环遍历数列,判断其中元素是否是66,如果是返回其索引! 5 # 但是,想一想,如果此数列有几百万个元素,这样遍历会很慢,如何查找最快?答案是:二分法 6 # 第一次,找到数列最中间的元素,比较它和66的大小,如果大于66,就说明66在它前面,前面的数又组成一个数列num_li_new_1, 7 # 如果它比66小,则说明66在它的后面,将其后面的数,组成一个新的数列:num_li_new_2 8 # 第二次,在num_li_new_1或者num_li_new_2中,继续按照第一的方法寻找下去。。。。。。 9 # 第n次,如果有该元素,一定会找到它,而且只有一个元素了! 10 11 #1)、第一次尝试用二分法 12 def find_num(list, target): 13 mid_index = len(list)//2 14 if list[mid_index] == target: 15 print('Congratunation! You get it!') 16 return mid_index 17 elif list[mid_index] > target: 18 new_list = list[:mid_index] 19 find_num(new_list, target) 20 else: 21 new_list = list[mid_index + 1:] 22 find_num(new_list, target) 23 24 res = find_num(num_li, 67) 25 print(res) 26 27 # 惊奇的发现,打印的结果是:None 28 # 分析未得到预想结果的原因: todo:没有接收返回值,也没有返回任何值! 所以为None 29 def find_num(list, target): # 第一步:list=num_li target = 67 30 mid_index = len(list) // 2 # 第二步:mid_index = 24//2 = 12 31 if list[mid_index] == target: # list[mid_index] = list[12] = 41 32 print('Congratunation! You get it!') 33 return mid_index 34 elif list[ mid_index ] > target: 35 new_list = list[ :mid_index ] 36 find_num(new_list, target) 37 else: #第三步:41 < 67 38 new_list = list[ mid_index + 1: ] # 第四步:new_list = list[13:] = [42,43,55,56,66,67,69,72,76,82,83,88] 39 find_num(new_list, target) # 第五步:find_num(new_list, 67)todo:没有接收返回值,也没有返回任何值! 40 41 def find_num(list, target): # 第六步:list=new_list target = 67 42 mid_index = len(list) // 2 # 第七步:mid_index = 12//2 = 6 43 if list[mid_index] == target: # list[mid_index] = list[6] = 69 44 print('Congratunation! You get it!') 45 return mid_index 46 elif list[ mid_index ] > target: # 第八步:69 > 67 47 new_list = list[ :mid_index ] # 第九步:new_list = list[:6] = [42,43,55,56,66,67] 48 find_num(new_list, target) # 第十步:find_num(new_list, 67) todo:没有接收返回值,也没有返回任何值! 49 else: 50 new_list = list[ mid_index + 1: ] # 51 find_num(new_list, target) # 52 53 def find_num(list, target): # 第十一步:list=new_list target = 67 54 mid_index = len(list) // 2 # 第十二步:mid_index = 6//2 = 3 55 if list[mid_index] == target: # list[mid_index] = list[3] = 56 56 print('Congratunation! You get it!') 57 return mid_index 58 elif list[ mid_index ] > target: # 59 new_list = list[ :mid_index ] 60 find_num(new_list, target) # 第十步:find_num(new_list, 67) 61 else: # 第十三步:56 < 67 62 new_list = list[mid_index + 1:] # 第十四步:new_list = list[4:] = [66,67] 63 find_num(new_list, target) # 第十五步: find_num(new_list, 67) todo:没有接收返回值,也没有返回任何值! 64 65 def find_num(list, target): # 第十六步: list=new_list target = 67 66 mid_index = len(list)//2 # 第十七步:mid_index = 2//2 = 1 67 if list[mid_index] == target: # 第十八步:list[mid_index] = list[1] = 67 正好相等! 68 print('Congratunation! You get it!') # 第十九步:输出Congratunation! You get it! 69 return mid_index # 第二十步:将mid_index = 1 todo 返回给调用该函数的地方:即第十五步 70 elif list[mid_index] > target: 71 new_list = list[:mid_index] 72 find_num(new_list, target) 73 else: 74 new_list = list[mid_index + 1:] 75 find_num(new_list, target) 76 77 #2)、第二次尝试用二分法 78 79 def find_num(list, target): 80 mid_index = len(list)//2 81 if list[mid_index] == target: 82 print('Congratunation! You get it!') 83 return mid_index 84 elif list[mid_index] > target: 85 new_list = list[:mid_index] 86 return find_num(new_list, target) 87 else: 88 new_list = list[mid_index + 1:] 89 return find_num(new_list, target) 90 91 res = find_num(num_li, 67) 92 print(res) 93 94 # 继续惊奇的发现,结果是:0,这并不是我们预想的结果! 95 # 原因分析:索引乱了,我们切分数列后,用的是新的索引! 96 97 # 3)、第三次尝试用二分法 98 99 #def find_num(list, target, start = 0, end = len(list)): #TypeError: object of type 'type' has no len() 100 def find_num(list, target, start = 0, end = None): 101 end = len(list) if end is None else end 102 # mid_index = len(list)//2 # 有时会报错:IndexError: list index out of range 103 mid_index = (end - start)//2 + start # 104 if list[mid_index] < target: 105 #new_list = list[ mid_index + 1:end ] # 加start和end后,不用传了,否者列表会越界! 106 return find_num(list, target, start=mid_index + 1, end=end) 107 elif list[mid_index] > target: 108 #new_list = list[start:mid_index] 109 return find_num(list, target, start=start, end=mid_index) 110 else: 111 print('Congratunation! You get it!') 112 return mid_index 113 114 res = find_num(num_li, 66) 115 print(res) 116 117 # 结果是出现了,还发现一个问题,如果查找的数不在列表中,会报错:RecursionError: maximum recursion depth exceeded in comparison 118 119 # 4、第四次 120 def find_num(list, target, start = 0, end = None): 121 end = len(list) if end is None else end 122 if end > start: 123 mid_index = (end - start)//2 + start # 124 if list[mid_index] < target: 125 return find_num(list, target, start=mid_index + 1, end=end) 126 elif list[mid_index] > target: 127 return find_num(list, target, start=start, end=mid_index) 128 else: 129 print('Congratunation! You get it!') 130 return mid_index 131 else: 132 return '该数列中没有你找的数!' 133 134 res = find_num(num_li, 44) 135 print(res)