Python數據結構之最短路徑
單源點最短路徑之Dijkstra算法
算法步驟:
-
把V分成兩組
(1) S: 以求出最短路徑的頂點的集合
(2) T = V - S : 尚未確定最短路徑的頂點集合。
-
將T中頂點按最短路徑遞增的次序加入到S中。
保證:
(1)從源點到S中各頂點的最短路徑長度都不大於從到T中任何頂點的最短路徑長度。
(2)每個頂點對應一個距離值:
S中頂點:從到此頂點的最短路徑長度,
T中頂點:從到此頂點的只包括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),若存在弧,則對應的元素爲權重;否則爲無窮。算法進行時,逐步試着在原路徑中增加中間結點,若加入中間頂點後路徑變短,則修改之;否則,維持原值。所有頂點試探完畢,算法結束。
代碼:
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實現迪傑斯特拉算法