Python數據結構之圖最短路徑

Python數據結構之最短路徑

單源點最短路徑之Dijkstra算法

算法步驟:

  1. 把V分成兩組

    (1) S: 以求出最短路徑的頂點的集合

    (2) T = V - S : 尚未確定最短路徑的頂點集合。

  2. 將T中頂點按最短路徑遞增的次序加入到S中。

保證

(1)從源點v0v_0到S中各頂點的最短路徑長度都不大於從v0v_0到T中任何頂點的最短路徑長度。

(2)每個頂點對應一個距離值:

S中頂點:從v0v_0到此頂點的最短路徑長度,

T中頂點:從v0v_0到此頂點的只包括S中頂點作中間頂點的最短路徑長度。

代碼:

(1) 訪問頂點類

class VisitedVertex:
    """訪問頂點類"""

    def __init__(self, length: int, index: int):
        """
        :param length:頂點個數
        :param index: 查詢的單原點
        """

        self.index = index
        self.ver = None

        self.already_array = [0] * length  # 標識已訪問過的結點
        self.pre_visited = [0] * length  # 保存前驅結點中繼節點
        self.dis = [float("inf")] * length  # 記錄最短距離,初始化無窮

        # 初始化自身到自身的距離爲0
        self.dis[index] = 0
        self.already_array[index] = 1

    def is_visited(self, index: int):
        """結點是否已經被訪問"""

        return self.already_array[index] == 1

    def update_dis(self, index: int, length: int):
        """更新最短路徑"""

        self.dis[index] = length

    def updata_pre(self, pre: int, index: int):
        """更新頂點的前驅結點"""

        self.pre_visited[pre] = index

    def get_dis(self, index: int):
        """得到距離"""
        return self.dis[index]

    def update_arr(self):

        min_val = float("inf")
        index = 0
        for i in range(len(self.already_array)):
            if self.already_array[i] == 0 and self.dis[i] < min_val:
                min_val = self.dis[i]
                index = i

        #  更新頂點
        self.already_array[index] = 1
        return index

    def show_result(self):

        print("輸出結果:")
        for item in self.already_array:
            print(item, end=" ")

        print()
        for item in self.pre_visited:
            print(item, end=" ")
        print()

        for item in self.dis:
            print(item, end=" ")
        print()

        self.ver = Graph(vertex, matrix)
        count: int = 0
        for item in self.dis:
            if item != float("inf"):
                print("{}->{}:distance:{}".format(self.ver.vertex[self.index], self.ver.vertex[count], self.dis[count]))
                count += 1

(2) 創建鄰接圖

class Graph:
    """構建圖"""

    def __init__(self, vertex: [], matrix: []):

        self.vertex = vertex  # 頂點
        self.matrix = matrix  # 鄰接矩陣
        self.vv = None

    def show_djs(self):

        self.vv.show_result()

    def show_graph(self):
        """顯示圖"""

        for col in self.matrix:
            print(col)

    def djs(self, index: int):
        """迪傑斯塔拉算法"""
        self.vv = VisitedVertex(len(self.vertex), index)
        #  第一次更新直接相連的頂點
        self.updata(index)

        #  加入n-1個結點
        for j in range(1, len(self.vertex)):
            # 中間結
            index = self.vv.update_arr()
            #  修改路徑
            self.updata(index)

    def updata(self, index):
        """更最短S集合中的最短路徑"""

        length: int = 0
        for j in range(len(self.matrix[index])):
            # 路徑長度遞增原則
            length = self.vv.get_dis(index) + self.matrix[index][j]
            
            # 第一前驅爲查詢結
            if not self.vv.is_visited(j) and length < self.vv.get_dis(j):
                self.vv.updata_pre(j, index)
                self.vv.update_dis(j, length)

if __name__ == "__main__":
    vertex: [] = ["A", "B", "C", "D", "E", "F", "G"]
    matrix: [] = [[0 for col in range(len(vertex))] for row in range(len(vertex))]
    # 用來表示一個極大的數
    F: float = float('inf')
    matrix[0] = [0, 5, 7, F, F, F, 2]
    matrix[1] = [5, 0, F, 9, F, F, 3]
    matrix[2] = [7, F, 0, F, 8, F, F]
    matrix[3] = [F, 9, F, 0, F, 4, F]
    matrix[4] = [F, F, 8, F, 0, 5, 4]
    matrix[5] = [F, F, F, 4, 5, 0, 6]
    matrix[6] = [2, 3, F, F, 4, 6, 0]
    g = Graph(vertex, matrix)
    g.show_graph()
    g.djs(6)
    g.show_djs()

多源點最短路之Floyd算法

目標:計算出圖中各個頂點之間的最短路徑

算法步驟:
初始時設置一個n階方陣,令其對角線元素爲0(即自身到自身的路徑爲0),若存在弧<vi,vj><v_i, v_j>,則對應的元素爲權重;否則爲無窮。算法進行時,逐步試着在原路徑中增加中間結點,若加入中間頂點後路徑變短,則修改之;否則,維持原值。所有頂點試探完畢,算法結束。

代碼:

1)初始化矩陣1

# matrix 爲鄰接矩陣形式
matrix[0] = [0, 5, 7, F, F, F, 2]
matrix[1] = [5, 0, F, 9, F, F, 3]
matrix[2] = [7, F, 0, F, 8, F, F]
matrix[3] = [F, 9, F, 0, F, 4, F]
matrix[4] = [F, F, 8, F, 0, 5, 4]
matrix[5] = [F, F, F, 4, 5, 0, 6]
matrix[6] = [2, 3, F, F, 4, 6, 0]

2)Floyd核心算法(不斷詢問新的結點的加入有沒使得原來的路徑更短

    def floyd(self):
        """Floyd算法:"""

        length: int = 0
        for k in range(len(self.dis)):  #  中間結點(新節點)
            
            for i in range(len(self.dis)):
                for j in range(len(self.dis)):
                    length = self.dis[i][k] + self.dis[k][j]
                    if length < self.dis[i][j]:
                        self.dis[i][j] = length
                        self.pre[i][j] = self.pre[k][j]

參考

數據結構與算法–弗洛伊德算法 Python實現弗洛伊德算法 一步一步帶你實現弗洛伊德算法

數據結構與算法–迪傑斯特拉算法 Python實現迪傑斯特拉算法 一步一步帶你用Python實現迪傑斯特拉算法

數據結構與算法基礎–第11周08–6.6圖的應用8–6.6.2最短路徑3–Floyd算法

數據結構與算法基礎–第11周07–6.6圖的應用7–6.6.2最短路徑2–Dijkstra算法

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章