狄克斯特拉算法用于在加权图中查找最短路径
狄克斯拉特算法
迪杰斯特拉算法主要特点是从起始点开始,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
以下图为例,演示如何实现狄克斯特拉算法:
1.需要3个散列表:
graph # 实现图,并显示边的权重
costs # 储存每个节点的开销
parents # 储存父节点
2.代码分别如下:
# 创建一个散列表记录节点的邻居,再创建一个散列表记录边的权重
graph = dict()
graph["start"] = {}
graph["start"]["a"] = 6 # 起点start节点的邻居
graph["start"]["b"] = 2
print("起始节点的邻居及边的权重:", graph["start"]) # 如果要获取起始节点的所有邻居和边的权重,可以这么做
print("起始节点的所有邻居:", graph["start"].keys()) # 获取所有邻居
print("起始节点到’a‘节点的边的权重:", graph["start"]["a"]) # 获取边的权重
print("\n")
graph["a"] = {}
graph["a"]["fin"] = 1 # a节点的邻居
graph["b"] = {}
graph["b"]["a"] = 3
graph["b"]["fin"] = 5
graph["fin"] = {} # 终点fin节点没有邻居
# 创建开销表
infinity = float("inf") # 表示无穷大
costs = dict()
costs["a"] = 6
costs["b"] = 2
costs["fin"] = infinity
# 储存父节点
parents = dict()
parents["a"] = "start"
parents["b"] = "start"
parents["fin"] = None
3.狄克斯特拉算法思路:
1 | 有节点要处理 |
2 | 获取最近节点 |
3 | 更新邻居开销表 |
4 | 同时更新父节点 |
5 | 标记为处理过 |
6 | 再返回第一步 |
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)
4.找开销最低节点
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
"""
狄克斯拉特算法
寻找有权图中(没有权重为负的边情况下)权重最小的路径
"""
# 创建一个散列表记录节点的邻居,再创建一个散列表记录边的权重
graph = dict()
graph["start"] = {}
graph["start"]["a"] = 6 # 起点start节点的邻居
graph["start"]["b"] = 2
print("起始节点的邻居及边的权重:", graph["start"]) # 如果要获取起始节点的所有邻居和边的权重,可以这么做
print("起始节点的所有邻居:", graph["start"].keys()) # 获取所有邻居
print("起始节点到’a‘节点的边的权重:", graph["start"]["a"]) # 获取边的权重
print("\n")
graph["a"] = {}
graph["a"]["fin"] = 1 # a节点的邻居
graph["b"] = {}
graph["b"]["a"] = 3
graph["b"]["fin"] = 5
graph["fin"] = {} # 终点fin节点没有邻居
# 创建开销表
infinity = float("inf") # 表示无穷大
costs = dict()
costs["a"] = 6
costs["b"] = 2
costs["fin"] = infinity
# 储存父节点
parents = dict()
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("起点到终点最小开销为:", cost)
最终代码
class DijkstraAlgorithm:
def __init__(self, graph):
self.graph = graph
def find_lowest_cost_node(self, costs, processed):
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
def find_shortest_path(self, start, end):
infinity = float("inf")
# 初始化开销表、父节点和处理过的节点列表
costs = {node: infinity for node in self.graph}
costs[start] = 0
parents = {node: None for node in self.graph}
processed = []
# 查找最短路径
node = self.find_lowest_cost_node(costs, processed)
while node is not None:
cost = costs[node]
neighbors = self.graph[node]
for neighbor in neighbors:
new_cost = cost + neighbors[neighbor]
if costs[neighbor] > new_cost:
costs[neighbor] = new_cost
parents[neighbor] = node
processed.append(node)
print(f"节点{node}已被处理过")
print(f"开销表更新为:{costs}")
node = self.find_lowest_cost_node(costs, processed)
# 输出最短路径和总开销
path = []
current = end
while current != start:
path.insert(0, current)
current = parents[current]
path.insert(0, start)
return path, costs[end]
# 测试
if __name__ == "__main__": # 图的简化代码
graph = {
"start": {"a": 6, "b": 2},
"a": {"fin": 1},
"b": {"a": 3, "fin": 5},
"fin": {}
}
algorithm = DijkstraAlgorithm(graph)
shortest_path, total_cost = algorithm.find_shortest_path("start", "fin")
print("最短路径:", shortest_path)
print("总开销:", total_cost)
结果