目录
宽度优先遍历
先遍历与当前结点相邻的结点,再遍历深一层的结点,层层递进,直到找到和合适的结果。
ABCDEFGHIJK和ABCDEF
特点:求解问题时,大部分情况下,不需要遍历完整张图。
实现方法:队列。
应用:求无权图的最短路径。
遍历步骤:
1. 定义一个操作队列Que,一个记录已经扫描过节点的数组Arr和一个遍历结果数组res。
2. 给定起始节点start,执行起始节点入队和加入数组Arr。
3. 执行扫描(只要队列不为空):
出队操作,并把出队节点v更新为新的起始节点start。
扫描起始节点start相邻(连接)的节点,通过Arr数组判断是否已被扫描过:
若扫描过,则继续。
若没有,则入队和加入数组Arr。
当前出队的节点v加入结果数组res。
深度优先遍历
一条路走到黑,走不通了再回到上一个岔路口,直到走完整张图。
ABDHIEJCFGK和ABDFEC
特点:求解问题时,需要遍历整张图。
实现方法:栈。
应用:求有多少个解,求有多少条路径,求最大路径等类似的问题。
遍历步骤:
1. 定义一个操作栈stack,一个记录已经扫描过节点的数组Arr和一个遍历结果数组res。
2. 给定起始节点start,执行起始节点入栈和加入数组Arr。
3. 执行扫描(只要栈不为空):
出栈操作,并把出栈节点v更新为新的起始节点start。
扫描起始节点start相邻(连接)的节点,通过Arr数组判断是否已被扫描过:
若扫描过,则继续。
若没有,则入栈和加入数组Arr。
当前出栈的节点v加入结果数组res。
注:BFS和DFS在遍历搜索时路径可能不唯一
如DFS:
python代码
宽度优先遍历
# 构造图
graph = {"A": ['B', 'C'],
"B": ['A', 'C', 'D'],
"C": ['A', 'B', 'D', 'E'],
"D": ['B', 'C', 'E', 'F'],
"E": ['C', 'D'],
"F": ['D']}
# graph图结构,start_v起始结点
def BFS(graph, start_v):
queue = [] # 队列
check = set() # 已经访问过
queue.append(start_v) # 放入起始结点
check.add(start_v) # 放入起始结点
# 遍历访问图
while len(queue) > 0:
vertex = queue.pop(0)
nodes = graph[vertex]
# 从当前结点相连接的结点中寻找
for v in nodes:
# 判断是否已经访问过,没有则访问
if v not in check:
queue.append(v)
check.add(v)
print(vertex) # 依次访问的节点
if __name__=="__main__":
# 宽度优先遍历
BFS(graph, 'A')
深度优先遍历
# 构造图
graph = {"A": ['B', 'C'],
"B": ['A', 'C', 'D'],
"C": ['A', 'B', 'D', 'E'],
"D": ['B', 'C', 'E', 'F'],
"E": ['C', 'D'],
"F": ['D']}
# graph图结构,start_v起始结点
def DFS(graph, start_v):
stack = [] # 栈
check = set() # 已经访问过
stack.append(start_v) # 放入起始结点
check.add(start_v) # 放入起始结点
# 遍历访问图
while len(stack) > 0:
vertex = stack.pop()
nodes = graph[vertex]
# 从当前结点相连接的结点中寻找
for v in nodes:
# 判断是否已经访问过,没有则访问
if v not in check:
stack.append(v)
check.add(v)
print(vertex) # 依次访问的节点
if __name__=="__main__":
# 深度优先遍历
DFS(graph, 'A')
扩展
保存父结点
求最短距离(当前结点到起始结点)
graph = {"A": ['B', 'C'],
"B": ['A', 'C', 'D'],
"C": ['A', 'B', 'D', 'E'],
"D": ['B', 'C', 'E', 'F'],
"E": ['C', 'D'],
"F": ['D']}
# 记录父节点,求最短路径(距离)
def BFSsuper(graph, start_v):
queue = [] # 队列
check = set() # 已经访问过
parent = {start_v: None} # 记录父节点
queue.append(start_v) # 放入起始结点
check.add(start_v) # 放入起始结点
# 遍历访问图
while len(queue) > 0:
vertex = queue.pop(0)
nodes = graph[vertex]
# 从当前结点相连接的结点中寻找
for v in nodes:
# 判断是否已经访问过,没有则访问
if v not in check:
queue.append(v)
check.add(v)
parent[v] = vertex
#print(vertex) # 依次访问的节点
# 返回父结点
return parent
if __name__=="__main__":
# 扩展(记录父节点)
start_v = 'A'
parent = BFSsuper(graph, start_v)
print('-----')
print("结点", "父结点")
for key in parent:
print(key, parent[key])
print('-----')
# 求最短路径(距离),从一个节点到遍历的初始节点的路径,通过父节点查找,直到触顶结束
node_start = 'E'
print("结点{}到起始结点{}的最短路径为:" .format(node_start, start_v))
while node_start != None:
print(node_start, end=", ")
node_start = parent[node_start]
加权图
dijkstra算法
import math
import heapq
weightedGrah = {"A": {'B': 5, 'C': 1},
"B": {'A': 5, 'C': 2, 'D': 1},
"C": {'A': 1, 'B': 2, 'D': 4, 'E': 8},
"D": {'B': 1, 'C': 4, 'E': 3, 'F': 6},
"E": {'C': 8, 'D': 3},
"F": {'D': 6}}
# 初始化距离
def init_distance(graph, stat_v):
distance = {stat_v: 0} # 起始点距离标为0
# 其它点距离标为正无穷
for vertex in graph:
if vertex != stat_v:
distance[vertex] = math.inf
return distance
# 加权图,dijkstra算法,求最短路径(距离)
def dijkstra(graph, start_v):
# 创建优先队列
pqueue = []
heapq.heappush(pqueue, (0, start_v))
check = set() # 已经访问过
parent = {start_v: None} # 记录父节点
distance = init_distance(graph, start_v) # 统计当前结点到起始结点的距离
while len(pqueue) > 0:
pair = heapq.heappop(pqueue)
dist = pair[0]
vertex = pair[1]
check.add(vertex)
nodes = graph[vertex].keys()
for v in nodes:
if v not in check:
# 确保最短距离
if dist+graph[vertex][v] < distance[v]:
heapq.heappush(pqueue, (dist+graph[vertex][v], v))
parent[v] = vertex
distance[v] = dist+graph[vertex][v]
return parent, distance
if __name__=="__main__":
# 加权图
parent, distance = dijkstra(weightedGrah, 'A')
#print(parent)
print(distance)