Python算法——《算法图解》笔记
算法目录
-
二分查找
-
大O表示法
-
选择排序
-
递归
-
快速排序,分而治之(D&C)
-
散列表——字典
-
广度优先搜索——BFS
-
Dijkstra算法
-
贪婪算法
二分查找
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 要求list是有序表,num是要查找的数字 2 # 二分查找貌似只能查找数值表 3 def binary_search(list, num): 4 low = 0 5 high = len(list) - 1 # 因为python数组(列表)是从0开始索引的 6 7 while low <= high: 8 mid = (low + high) 9 guess = list[mid] 10 if guess == num: 11 return "found it is " + str(mid) 12 if guess > num: 13 high = mid - 1 14 else: 15 low = mid + 1 16 return "not found" 17 18 # python数组不同于matlab数组,python中间要用逗号隔开,而matlab不用 19 my_list = [1, 3, 5, 7, 9, 11, 13] 20 print(binary_search(my_list, 6)) 21 print(binary_search(my_list, 9))
大O表示法
1. 能够比较操作数,表示算法运行时间的增速
2. 给出了一个时间的上限
3. 算法的速度并非时间,而是操作数的增速
4. O(logn)——对数时间(二分查找)
5. O(n)——线性时间(顺序查找)
6. O(n*logn)——快速排序
7. O(n^2)——选择排序
8. O(n!)——旅行商问题的解决办法
9. 常量并不会影响到大O表示法
选择排序
* 计算机内存如同一大堆抽屉
* 需要存储多个元素时可采用链表或数组
* 数组元素都在一起,因此读取速度快
* 链表是分开的,但是插入和删除速度很快
* 链表数组查找比数组慢,比链表快;插入比数组快,与链表相当
* 同一数组元素的类型均相同
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 寻找数组中的最小值的索引 2 def find_smallest_index(arr): 3 smallest = arr[0] 4 smallest_index = 0; 5 # python中检查数组长度的函数是len,而matlab中是length 6 for i in range(1, len(arr)): 7 if arr[i] < smallest: 8 smallest = arr[i] 9 smallest_index = i 10 return smallest_index 11 12 # 对数组进行排序 13 def selection_insort(arr): 14 # create new array 15 new_arr = [] 16 for i in range(len(arr)): 17 smallest_index = find_smallest_index(arr) 18 # array.pop()只能根据索引值弹出元素,so pop()应传入索引值 19 new_arr.append(arr.pop(smallest_index)) 20 return new_arr 21 22 mess_arr = [3, 1, 9, 2, 5, 4] 23 print("This is uninsort array: " + str(mess_arr)) 24 insorted_arr = selection_insort(mess_arr) 25 print("This is insorted array: " + str(insorted_arr))
递归
* 使用循环程序性能可能更高,使用递归程序可能更容易理解
* 递归条件——让函数调用自己;基线条件——让函数不再调用自己
* 所有函数调用都进入递归调用栈
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 一个计算数学阶乘的递归调用 2 def func(x): 3 if x == 1: 4 return 1 5 else: 6 return x * func(x-1) 7 8 print(func(3)) 9 10 11 #一个计算数组和的递归调用 12 def func(arr): 13 if arr == []: 14 return 0 15 else: 16 # 这里不能用arr[0] + func()因为基线条件是arr==[]当arr 17 # 只有一个元素时python会将arr变为一个int数值,而不会是数组 18 return arr.pop() + func(arr) 19 20 arr = [2, 3, 4] 21 print(func(arr))
快速排序,分而治之(D&C)
* 找出基线条件(很可能是一个空数组或者只包含一个元素的数组)
* 不断将问题分解直至满足基线条件
* 快速排序:
* 选取基准值
* 将数组分为两个子数组:小于基准值的元素和大于基准值的元素
* 对这两个子数组进行快速排序
View Code
View Code
View Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 快速排序——by myself 2 def quickly_sort(arr): 3 # 两个基线条件 4 if len(arr) < 2: 5 return arr 6 # 直接选取数组元素第一个当作基准值——递归条件 7 reference_value = arr[0] 8 larger_arr = [] 9 smaller_arr = [] 10 for i in range(1,len(arr)): 11 if arr[i] > reference_value: 12 larger_arr.append(arr[i]) 13 # arr.pop(i) 14 else: 15 smaller_arr.append(arr[i]) 16 # arr.pop(i) 17 return quickly_sort(smaller_arr) + [reference_value] + quickly_sort(larger_arr) 18 19 mess_arr = [3, 1, 9, 2, 5, 4] 20 print("This is uninsort array: " + str(mess_arr)) 21 insorted_arr = quickly_sort(mess_arr) 22 print("This is insorted array: " + str(insorted_arr))
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 快速排序——by others 2 def quickly_sort(arr): 3 # 基线条件 4 if len(arr) < 2: 5 return arr 6 else: 7 # 选取基准值——递归条件 8 pivot = arr[0] 9 10 # 简洁明了选出较大数组与较小数组 11 larger = [i for i in arr[1:] if i > pivot] 12 smaller = [i for i in arr[1:] if i <= pivot] 13 # 递归调用 14 return quickly_sort(smaller) + [pivot] + quickly_sort(larger) 15 16 mess_arr = [3, 1, 9, 2, 5, 4] 17 print("This is uninsort array: " + str(mess_arr)) 18 insorted_arr = quickly_sort(mess_arr) 19 print("This is insorted array: " + str(insorted_arr))
散列表——字典
* 散列函数——将输入映射到数字;同一输入映射一致,不同输入映射到不同的数字
* 良好散列表包括:较低的填装因子0.7以下,良好的散列函数SHA函数
* 散列表查找(O(1))、删除、插入都非常快
* 散列表适用于模拟映射关系、防止重复以及缓存数据
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 散列表——字典 2 # 创建字典的两种方案 3 price_list = dict() 4 price_list = {} 5 6 7 # 添加数据 8 price_list["apple"] = 0.67 9 price_list["milk"] = 1.49 10 price_list["bread"] = 0.49 11 12 print(price_list) 13 print(price_list.keys()) 14 print(price_list.values()) 15 print(price_list.items()) 16 17 # 判断是否在散列表中 18 flag = price_list.get("apple") 19 print(flag) 20 # 不同大小写诗不同与阿奴 21 flag = price_list.get("Apple") 22 print(flag) 23 flag = price_list.get("banana") 24 print(flag)
广度优先搜索——BFS
* 用于解决最短路径
* 利用import collection import deque 创建一个双端队列
* 栈是LIFO,队列是FIFO
* 广度优先搜索时,对于检查过的人不能再去检查
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 广度优先搜索示例 2 from collections import deque 3 4 # 创建一个关系图(散列表) 5 graph = {} 6 # 单引号与双引号基本无使用上的区别,但是三引号可实现跨行输出 7 graph["you"] = ["alice", 'bob', "claire"] 8 graph["alice"] = ['peggy'] 9 graph["bob"] = ["anuj", 'peggy'] 10 graph['claire'] = ["thom", 'jonny'] 11 graph["peggy"] = [] 12 graph["anuj"] = [] 13 graph["thom"] = [] 14 graph["jonny"] = [] 15 16 17 search_queue = deque() 18 search_queue += graph["you"] 19 20 # 判断是否为经销商 21 def person_is_seller(name): 22 return (name[-1] == 'o') 23 24 def search(search_queue): 25 searched = [] 26 while search_queue: 27 28 person = search_queue.popleft() #取出队列左边第一个元素 29 # 检查后不再检查 30 if person not in searched: 31 if person_is_seller(person): 32 print(person + " is a mago seller !") 33 return True 34 else: 35 # 把TA的朋友加入搜索队列 36 search_queue += graph[person] 37 searched.append(person) 38 print("Can't find mago seller in your friends") 39 return False 40 search(search_queue)
Dijkstra算法
* 找出目前最便宜的节点
* 更新该节点的邻居的开销
* 重复这个过程,直到对图中所有节点都这么做了
* 计算最终路径
* Dijkstra算法只适用与有向无环图
* 对于包含负权边的图,请使用贝尔曼-福德算法graph
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # Dijkstra算法 2 3 # 寻找lowest_cost_node 4 def find_lowest_cost_node(costs): 5 lowest_cost = float("inf") 6 lowest_cost_node = None 7 for node in costs: 8 cost = costs[node] 9 if cost < lowest_cost and node not in processed: 10 lowest_cost = cost 11 lowest_cost_node = node 12 return lowest_cost_node 13 14 15 # Create a graph 16 graph = {} 17 graph['start'] = {} 18 graph['start']['a'] = 6 19 graph['start']['b'] = 2 20 graph['a'] = {} 21 graph['a']['fin'] = 1 22 graph['b'] = {} 23 graph['b']['fin'] = 5 24 graph['b']['a'] = 3 25 graph['fin'] = {} 26 27 28 # create a cost dict 29 infinity = float('inf') 30 costs = {} 31 costs['a'] = 6 32 costs['b'] = 2 33 costs['fin'] = infinity 34 35 # creata a parent dict 36 parents = {} 37 parents['a'] = "start" 38 parents['b'] = "start" 39 parents['fin'] = None 40 41 42 # record processed nodes 43 processed = [] 44 45 46 node = find_lowest_cost_node(costs) 47 while node is not None: 48 cost = costs[node] 49 neighbors = graph[node] 50 for n in neighbors.keys(): 51 new_cost = cost + neighbors[n] 52 if costs[n] > new_cost: 53 costs[n] = new_cost 54 parents[n] = node 55 processed.append(node) 56 node = find_lowest_cost_node(costs) 57 58 route = ['fin'] 59 node = parents['fin'] 60 route.append(node) 61 node = parents[node] 62 route.append(node) 63 node = parents[node] 64 route.append(node) 65 66 67 print(route)
贪婪算法
* 衡量标准:速度有多快;得到的近似解与最优解的接近程度
* 易于实现,运行速度快
* 识别NP完全问题
* 随着元素的增加操作速度极速增加
* 涉及“所有组合”的问题通常是NP完全问题
* 问题可转换为集合覆盖问题和旅行商问题