这次我们来学习一下图文结合的狄克斯特拉算法
狄克斯特拉算法包含4个步骤
(1) 找出最便宜的节点,即可在最短时间内前往的节点
(2) 对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新其开销
(3) 重复这个过程,直到对图中的每个节点都这样做了
(4) 计算最终路径
术语:
狄克斯特拉算法用于每条边都有关联数字的图,这些数字称为权重(weight),带权重的图称为加权图(weighted graph),不带权重的图称为非加权图(unweighted graph)
计算非加权图的最短距离既可以用广度优先搜索,也可以用狄克斯特拉算法,但是有可能出现"环"的情况
在狄克斯特拉算法中,绕环的路径不可能是最短路径
狄克斯特拉算法只适用有向无环的图
最短路径指的并不一定是物理距离,也可能是让某种度量指标最小
负权边:
对有负权重的图使用狄克斯特拉算法,会错误的路径,因此.如果有负权边,就不能使用狄克斯特拉算法
在包含负权边的图中,要找出最短路径,可使用另一种算法——贝尔曼.福德算法(Bellman-Ford algorithm)
案例
找到从起点到终点的最小的开销
graph = {
} # 创建一个散列表
# 嵌套散列表去包含起点到各个的节点以及权重
graph["start"] = {
}
graph["start"]["a"] = 6
graph["start"]["b"] = 2
graph["a"] = {
}
graph["a"]["fin"] = 1
graph["b"] = {
}
graph["b"]["a"] = 3
graph["b"]["fin"] = 5
graph["fin"] = {
} # 终点没有邻居
# 节点的开销指的是从起点出发前往该节点需要多长时间
infinity = float("inf") # 创建一个开销表
costs = {
}
costs["a"] = 6
costs["b"] = 2
costs["fin"] = infinity
parents = {
} # 创建一个存储父节点的散列表
parents["a"] = "start"
parents["b"] = "start"
parents["fin"] = None
processed = [] # 创建一个数组,用于记录处理过的节点
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:
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)
print(f"起点到终点的最小开销为:{costs['fin']}") # 找出接下来要处理的节点并循环