迪杰斯特拉算法(Dijkstra)- Python实现

迪杰斯特拉的关键理念:找出图中开销最低的节点,并保证没有到该节点开销更低的路径

以下面的图为例:

要解决这个问题,需要三个散列表: 

graph
起点A6
B2
Afinal1
BA3
final5
final-

 

costs
A6
B2
终点
parents
Astart
Bstart
终点-

随着算法的进行,你将不断更新散列表costs和parents

迪杰斯特拉算法的4个步骤:

  1. 找出开销最小的节点,即可在最短时间内前往的节点
  2. 对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新其开销
  3. 重复这个过程,直到对图中的每个节点都这样做了
  4. 计算最终路径

算法流程图

Python代码:

# -*- encoding: utf-8 -*-

# 找出开销最低的节点
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


if __name__ == "__main__":
    # 构造有向赋权图 graph 存储所有节点的邻居
    graph = {}
    graph["start"] = {} # 起点
    graph["start"]["a"] = 6
    graph["start"]["b"] = 2
    graph["a"] = {} # a节点
    graph["a"]["final"] = 1
    graph["b"] = {} # b节点
    graph["b"]["a"] = 3
    graph["b"]["final"] = 5
    graph["final"] = {} # 终点没有任何邻居

    # 构造散列表costs 存储每个节点的开销
    # 节点的开销是指的从起点出发前往该节点需要多长时间
    # 对于还不知道的开销,你将其设置为无穷大
    infinity = float ("inf")
    costs = {}
    costs["a"] = graph["start"]["a"]
    costs["b"] = graph["start"]["b"]
    costs["final"] = infinity

    # 还需要一个存储父节点的散列表
    parents = {}
    parents["a"] = "start"
    parents["b"] = "start"
    parents["final"] = None

    # 最后你需要一个数组,记录处理过的节点
    processed = []

    node = find_lowest_cost_node(costs) # 找出开销最低的节点
    while node is not None:
        cost = costs[node] # 获取该节点的开销
        neighbors = graph[node] # 获取该节点的邻居 neighbors是一个散列表
        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)

    child = "final"
    parent = ["final"]
    while child != "start":
        parent.append(parents[child])
        child = parents[child]
        # print(parent)

    print("最短路径为:", parent[::-1])
    print("最短路径长度为:%d" % costs["final"])

注意:不能将迪杰斯特拉算法用于包含负权边的图。因为迪杰斯特拉算法这样假设:对于处理过的节点,没有前往该节点的更短路径,负权边会导致这个算法不管用。负权边的图中,要找出最短路径,可以使用另一种算法——贝尔曼-福德算法(Bellman-Ford algorithm)。

 

  • 5
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值