前言
美好的周末,来看算法图解咯~
广度优先搜索
- 用图解决最短路径问题的算法被称为广度优先搜索
- 图由节点和边组成
- 用于回答两个问题
- 第一类问题:从节点A出发,有前往节点B的路径吗?
- 第二类问题:从节点A出发,前往节点B的哪条路径最短?
- 队列先进先出(FIFO),栈后进先出(LIFO)
- python可以用字典键值对表示有向图的结点
-
graph = {} graph["you"] = ["alice", "bob", "claire"] graph["bob"] = ["anuj", "peggy"] graph["alice"] = ["peggy"] graph["claire"] = ["thom", "jonny"] graph["anuj"] = [] graph["peggy"] = [] graph["thom"] = [] graph["jonny"] = []
-
- 算法原理
-
from collections import deque search_queue = deque() # 创建一个队列 search_queue += graph["you"] # 将你的邻居都加入到这个搜索队列中 def person_is_seller(name): # 检查人的姓名是否以m结尾(芒果销售商) return name[-1] == 'm' while search_queue: # 只要队列不为空, person = search_queue.popleft() # 就取出其中的第一个人 if person_is_seller(person): # 检查这个人是否是芒果销售商 print person + " is a mango seller!" # 是芒果销售商 return True else: search_queue += graph[person] # 不是芒果销售商。将这个人的朋友都加入搜索队列 return False # 如果到达了这里,就说明队列中没人是芒果销售商
-
- 还要添加一个数组记录已检查过的人防止死循环
-
def search(name): search_queue = deque() search_queue += graph[name] searched = [] # 这个数组用于记录检查过的人 while search_queue: person = search_queue.popleft() if not person in searched: # 仅当这个人没检查过时才检查 if person_is_seller(person): print person + " is a mango seller!" return True else: search_queue += graph[person] searched.append(person) # 将这个人标记为检查过 return False
-
- 广度优先搜索的运行时间:
- O(人数 + 边数),这通常写作O(V + E),其中V为顶点(vertice)数,E为边数
狄克斯特拉算法(Dijkstra’s algorithm)
- 找出加权图中总权重最小的路径,只适用于有向无环图(directed acyclicgraph,DAG)
- 四个步骤
- 如果有负权边,就不能使用狄克斯特拉算法,用贝尔曼-福德算法
- 算法编写
- 创建三个散列表,
- 图和权重,开销(是从起点出发前往该节点需要多长时间)和父节点
-
def find_lowest_cost_node(costs): # 找出开销最低的节点 lowest_cost = float("inf") # 表示正无穷 lowest_cost_node = None for node in costs: # 遍历所有的节点 cost = costs[node] if cost < lowest_cost and node not in processed: # 如果当前节点的开销更低且未处理过, lowest_cost = cost # 就将其视为开销最低的节点 lowest_cost_node = node return lowest_cost_node node = find_lowest_cost_node(costs) # 在未处理的节点中找出开销最小的节点 while node is not None: # 这个while循环在所有节点都被处理过后结束 cost = costs[node] neighbors = graph[node] for n in neighbors.keys(): # 遍历当前节点的所有邻居 new_cost = cost + neighbors[n] if costs[n] > new_cost: # 如果经当前节点前往该邻居更近, costs[n] = new_cost # 就更新该邻居的开销 parents[n] = node # 同时将该邻居的父节点设置为当前节点 processed.append(node) # 将当前节点标记为处理过 node = find_lowest_cost_node(costs) # 找出接下来要处理的节点,并循环
- 创建三个散列表,
后言
道理我都懂,但到时候实现的时候估计又是一脸懵了,无论怎么说,先理解算法思想吧!