數據結構和算法-最短路徑

針對無權圖能夠使用深度優先和廣度優先算法, 有權圖能夠使用最短路徑算法node

Dijkstra(迪傑斯特拉算法): 在有向加權圖中查找最短路徑python

注意: 該算法只適用於有向無環圖, 不適用於負權邊的狀況算法

思路:數據結構

  1. 找出距離起點最近的節點
  2. 對於該節點鄰居, 檢查是否有前往他們的更短路徑, 若是有就更新開銷
  3. 重複以上兩步, 直到全部節點運行過
  4. 找出最短路徑

下表爲要從起點到達終點, 數字爲花費的時間app

父節點 節點 花費
start A 6
start B 2
B A 5
B end 7
A end 6

上圖是按照以上步驟進行填充的數據結構和算法

  1. 找出start的鄰居節點AB, 其中B的花費最少
  2. 找出B節點的鄰居節點Aend, 更新到A節點的開銷
  3. 繼續對A節點進行, 從Aend花費最小, 更新Bend的開銷

因此最小距離爲start --> B --> A --> endcode

實現

利用最小堆實現, 時間複雜度: O(e * logv), e是邊的個數blog

# -*- coding:utf-8 -*-

'''
Dijkstra算法(最短路徑算法)

- 適用於有向有權無環圖
- 不適用於負權邊的狀況
'''

import heapq


class Graph(object):
    def __init__(self):
        self.graph = {}

    def add_edge(self, start: str, end: str, distance: float):
        self.graph.setdefault(start, {})
        self.graph[start][end] = distance


def dijkstra(start: str, end: str, graph: dict) -> list:
    visited = set()  # 存儲已經處理過的節點
    costs = {start: 0}

    queue = [(0, start)]
    path = {}  # 用於復原路徑

    while queue:
        dis, min_node = heapq.heappop(queue)
        if min_node == end:
            break

        if min_node not in visited:
            visited.add(min_node)

            neighbors = graph[min_node]
            for i, j in neighbors.items():
                new_dis = dis + j
                if (i not in costs) or (new_dis < costs[i]):
                    costs[i] = new_dis
                    heapq.heappush(queue, (new_dis, i))
                    path[i] = min_node

    res = []
    key = end
    while key != start:
        res.append(key)
        key = path[key]
    res.append(start)
    res.reverse()

    return res


if __name__ == '__main__':
    g1 = Graph()
    g1.add_edge('start', 'a', 3)
    g1.add_edge('start', 'b', 2)
    g1.add_edge('b', 'a', 6)
    g1.add_edge('b', 'end', 5)
    g1.add_edge('a', 'end', 1)
    assert dijkstra('start', 'end', g1.graph) == ['start', 'a', 'end']

    g2 = Graph()
    g2.add_edge('start', 'a', 5)
    g2.add_edge('start', 'b', 2)
    g2.add_edge('b', 'a', 1)
    g2.add_edge('b', 'end', 5)
    g2.add_edge('a', 'end', 1)
    assert dijkstra('start', 'end', g2.graph) == ['start', 'b', 'a', 'end']
  • 利用最小堆不斷找出開銷最小的節點
  • 當發現有到達某個節點的更短距離是更新該節點的距離

資料

  • < <漫畫算法> >
  • < <數據結構和算法> >

相關文章
相關標籤/搜索