美文网首页
常见算法7、狄克斯特拉算法 Dijkstra's algorit

常见算法7、狄克斯特拉算法 Dijkstra's algorit

作者: 四月不见 | 来源:发表于2021-12-15 00:23 被阅读0次

    一、简介

    前面章节介绍了使用广度优先搜索,设计找出段数最少的路径算法。但是路段最少并不表示速度最快,如果你需要找出最快的路径,就可以使用本章要介绍的狄克斯特拉算法 Dijkstra's algorithm

    如下图,给每个路段都加上它的耗时

    如果你使用广度优先搜索,你将找出起点到终点路段数最少的路径。

    但使用狄克斯特拉算法,你就可以找出起点到终点耗时最少的路径。

    狄克斯特拉算法用于每条边都有关联数字的图,这些数字称为权重。

    带权重的图称为加权图,不带权重的图称为非加权图。计算非加权图中的最短路径,可使用广度优先搜索。计算加权图中的最短路径,可使用狄克斯特拉算法。
    图还有可能有环,但狄克斯特拉算法只适用于有向无环图。

    二、实现原理

    如下图,使用狄克斯特拉算法计算最短路径。

    要编写解决这个问题的代码,首先需要三个散列表。

    表1、存储图中的所有节点和权重信息

    表2、存储存储每个节点的开销
    节点的开销指的是从起点出发前往该节点需要多长时间。对于还不知道的开销则设其为无穷大。

    表3、父节点的散列表

    最后,还需要一个数组,用于记录处理过的节点,因为对于同一个节点,你不用处理多次。

    算法原理大概如下:

    处理所有节点后,这个算法就结束了。

    三、代码实现:

    1、Python 3 :

    # the graph
    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"] = {} # 终点没有任何邻居了
    
    # the costs table
    infinity = float("inf") # 表示无穷大
    costs = {}
    costs["a"] = 6
    costs["b"] = 2
    costs["fin"] = infinity
    
    # the parents table
    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 ("Cost from the start to each node:")
    print (costs)
    print (parents)
    
    =============== 运行结果:===============
    Cost from the start to each node:
    {'a': 5, 'b': 2, 'fin': 6}
    {'a': 'b', 'b': 'start', 'fin': 'a'}
    

    2、PHP :

    $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"] = [];
    
    # the costs table
    $infinity = PHP_INT_MAX;
    $costs = [];
    $costs["a"] = 6;
    $costs["b"] = 2;
    $costs["fin"] = $infinity;
    
    # the parents table
    $parents = [];
    $parents["a"] = "start";
    $parents["b"] = "start";
    $parents["fin"] = null;
    
    $processed = [];
    
    // 在未处理的节点中找出开销最小的节点
    function findLowestCodeNode(array $costs) {
        $lowestCost = PHP_INT_MAX;
        $lowestCostNode = null;
        global $processed;
        foreach ($costs as $node => $cost) { //遍历所有节点
            if ($cost < $lowestCost && !array_key_exists($node, $processed)) {
                $lowestCost = $cost;
                $lowestCostNode = $node;
            }
        }
        return $lowestCostNode;
    }
    
    $node = findLowestCodeNode($costs);
    
    while ($node) {
        $cost = $costs[$node];
        $neighbors = $graph[$node];
        foreach (array_keys($neighbors) as $n) {
            $newCost = $cost + $neighbors[$n];
            if ($costs[$n] > $newCost) {
                $costs[$n] = $newCost;
                $parents[$n] = $node;
            }
        }
        $processed[$node] = true;
        $node = findLowestCodeNode($costs);
    }
    
    print("Cost from the start to each node:");
    var_dump($costs);
    var_dump($parents);
    
    =============== 运行结果:===============
    Cost from the start to each node:
    array(3) {
      ["a"]=>
      int(5)
      ["b"]=>
      int(2)
      ["fin"]=>
      int(6)
    }
    array(3) {
      ["a"]=>
      string(1) "b"
      ["b"]=>
      string(5) "start"
      ["fin"]=>
      string(1) "a"
    }
    

    参考

    1、《算法图解》https://www.manning.com/books/grokking-algorithms

    相关文章

      网友评论

          本文标题:常见算法7、狄克斯特拉算法 Dijkstra's algorit

          本文链接:https://www.haomeiwen.com/subject/hsyanltx.html