数据结构之图:加权有向图与dijkstra算法找到最短路径,Python——28
生活随笔
收集整理的這篇文章主要介紹了
数据结构之图:加权有向图与dijkstra算法找到最短路径,Python——28
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
加權(quán)有向圖與dijkstra算法找到最短路徑
加權(quán)有向圖的構(gòu)造
最短路徑問(wèn)題與最短路徑樹(shù)
最短路徑問(wèn)題(The shortest path problem)定義
- 最短路徑可以是時(shí)間花費(fèi)最短,也可以是距離最短,或是花費(fèi)最少
- 在圖論中,最短路徑問(wèn)題指的是一個(gè)graph中,想要找到兩個(gè)頂點(diǎn)之間的路徑使它們間連通的全部邊的權(quán)重和最小化
最短路徑的性質(zhì)
使用dijkstra算法找到最短路徑樹(shù)
最短路徑樹(shù)(Shortest-path tree)定義
- 給定一副加權(quán)有向圖和一個(gè)頂點(diǎn)s,以s為起點(diǎn)的一棵最短路徑樹(shù)是圖的一副子圖,它包含頂點(diǎn)s以及從s可達(dá)的所有頂點(diǎn)。這棵有向樹(shù)的根結(jié)點(diǎn)為s,樹(shù)的每條路徑都是有向圖中的一 條最短路徑。
去往dijkstra算法
- 加權(quán)有向圖的邊具有方向,其中_from是出發(fā)頂點(diǎn);_to是目的頂點(diǎn);weight是這條邊的權(quán)重。
加權(quán)有向圖的實(shí)現(xiàn)
去往dijkstra算法
- num_vertices 定義了圖中頂點(diǎn)的個(gè)數(shù);num_edges 為邊的數(shù)量,初始狀態(tài)下各頂點(diǎn)相互分隔,邊數(shù)量為0;adj_list 是一個(gè)列表,索引代表頂點(diǎn),每個(gè)值也是一個(gè)列表,儲(chǔ)存著對(duì)應(yīng)頂點(diǎn)通向的目的頂點(diǎn);
- add_edge(edge: DirectedEdge)傳入一個(gè)DirectedEdge對(duì)象,向adj_list中對(duì)應(yīng)位置添加一條有向邊;
- get_all_edges_of(v) 獲取傳入的頂點(diǎn)v的所有通往的邊
- get_all_edges() 獲取整張圖的所有的邊;
松弛方法relax的過(guò)程
- 當(dāng)前已經(jīng)存在一條最短路徑S->W且知道其路徑總權(quán)重SP_weight[w],現(xiàn)在要判斷下一條路徑S->V->W是否更短,則首先計(jì)算S->V的最短路徑的總權(quán)重SP_weight[V],然后再加上V->W的最短邊的權(quán)重,如果相加之和大于之前最短路徑的權(quán)重和SP_weight[W],則無(wú)需松弛,無(wú)需更新數(shù)據(jù)
- 當(dāng)從起點(diǎn)S到達(dá)V的最短路徑的權(quán)重之和加上從V到達(dá)W的權(quán)重小于從起點(diǎn)S到達(dá)W的最短路徑權(quán)重之和時(shí),則對(duì)應(yīng)松弛成功的情況,需要將從S到W的最短路徑權(quán)重之和SP_weight[W]更新為SP_weight[V] + [V到W邊的權(quán)重],到達(dá)終點(diǎn)前的最后一條邊last_edge要更新為[V→W]
- 頂點(diǎn)的松弛是基于邊的松弛完成的,只需要把某個(gè)頂點(diǎn)指出的所有邊松弛,那么該頂點(diǎn)就松弛完畢。例如要松弛頂點(diǎn)v,只需要遍歷v的鄰接表,把每一邊都松弛,那么頂點(diǎn)v就松弛了。
Python代碼實(shí)現(xiàn)dijkstra算法尋找最短路徑
from Structure.graph.DirectedEdge import DirectedEdge from Structure.graph.WeightedDigraph import WeightedDigraph from Structure.PriorityQueue.IndexMinPriorityQueue import IndexMinPriorityQueue from math import infclass DijkstraSP:def __init__(self, graph, start_vertex=0):self.graph = graphself.start_vertex = start_vertex# Each vertex(index) point to a minimum weight from the start vertex(0)self.SP_weight = [inf for _ in range(self.graph.num_vertices)]# Store the last SPT edge from 0 to the vertex(index)self.last_edge = [None for _ in range(self.graph.num_vertices)]# Store all edges? of the SPT(all the last_edge)# Index equals to vertex, element equals to edge.weight from the current vertexself.SPT_edge_weights = IndexMinPriorityQueue(self.graph.num_vertices) # num_vertices - 1 + 1self.SP_weight[start_vertex] = 0.0# Index equals to vertex, element equals to weightself.SPT_edge_weights.insert(start_vertex, 0.0)while self.SPT_edge_weights.size() > 0:min_weight_vertex = self.SPT_edge_weights.delete_min_and_get_index()# print(f"min_weight_vertex {min_weight_vertex}")self.relax(min_weight_vertex)def relax(self, v):"""Check if the total weight from 0 to v is lesser than from 0 to w"""# To relax a vertex is to relax all its edgesfor e in self.graph.get_all_edges_of(v):w = e.end()if self.SP_weight[v] + e.weight < self.SP_weight[w]:self.SP_weight[w] = self.SP_weight[v] + e.weightself.last_edge[w] = eif self.SPT_edge_weights.is_index_exist(w):self.SPT_edge_weights.change_item(w, e.weight)else:self.SPT_edge_weights.insert(w, e.weight)def sp_weight_to(self, v):"""Get the total weight of a shortest path from 0 to v"""return self.SP_weight[v]def has_path_to(self, v):"""Check if the start vertex to v is feasible"""# return self.graph.adj_list[v]return self.SP_weight[v] < infdef shortest_path_to(self, v):"""Get all the shortest path edges from 0 to v"""if not self.has_path_to(v):returnall_sp_edges = []while True:e = self.last_edge[v]if not e:breakall_sp_edges.insert(0, e)v = e.start()return all_sp_edges屬性和方法說(shuō)明
graph 接收傳入的圖對(duì)象;start_vertex 為要找出最短路徑樹(shù)的起始頂點(diǎn);
SP_weight是一個(gè)列表,索引代表當(dāng)前頂點(diǎn),值代表從起點(diǎn)出發(fā)到索引對(duì)應(yīng)頂點(diǎn)的最短路徑的權(quán)重和,它初始化儲(chǔ)存全部為無(wú)窮大inf,可以使搜尋時(shí)路徑時(shí)的初次權(quán)重比較一定會(huì)成功;
last_edge是一個(gè)列表,索引對(duì)應(yīng)著頂點(diǎn),儲(chǔ)存的值表示從起點(diǎn)到索引對(duì)應(yīng)頂點(diǎn)的最短路徑中的最后一條邊;
SPT_edge_weights是一個(gè)最小優(yōu)先隊(duì)列MinIndexPriorityQueue對(duì)象,索引代表頂點(diǎn),存入的值是從起點(diǎn)到當(dāng)前遍歷頂點(diǎn)的經(jīng)過(guò)松弛relax()后的路徑上的最后一條邊的權(quán)重,其實(shí)就是對(duì)應(yīng)的last_edge的權(quán)重
回到DirectedEdge
回到WeightedDigraph
其中用到的的索引最小優(yōu)先隊(duì)列IndexMinPriorityQueue傳送門
運(yùn)行測(cè)試:
if __name__ == '__main__':with open('../DSP.txt', 'r') as f:num_vertices = int(f.readline())num_edges = int(f.readline())graph = WeightedDigraph(num_vertices)edge = DirectedEdgefor _ in range(num_edges):_from, _to, weight = f.readline().split()# print(_from, _to, weight)graph.add_edge(edge(int(_from), int(_to), float(weight)))end = 6DSP = DijkstraSP(graph, 0)# print([e.start() for e in DSP.shortest_path_to(end)] + [end])print(DSP.sp_weight_to(end))print(DSP.has_path_to(end))for e in DSP.shortest_path_to(end):print(f"{e.start()}-->{e.end()}, {e.weight}")運(yùn)行結(jié)果:
1.5100000000000002 True 0-->2, 0.26 2-->7, 0.34 7-->3, 0.39 3-->6, 0.520 → 2 → 7 → 3 → 6
對(duì)比參考結(jié)果:
DSP.txt
8 15 4 5 0.35 5 4 0.35 4 7 0.37 5 7 0.28 7 5 0.28 5 1 0.32 0 4 0.38 0 2 0.26 7 3 0.39 1 3 0.29 2 7 0.34 6 2 0.40 3 6 0.52 6 0 0.58 6 4 0.93總結(jié)
以上是生活随笔為你收集整理的数据结构之图:加权有向图与dijkstra算法找到最短路径,Python——28的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java操作日志记录_通用日志记录(ja
- 下一篇: 数据结构链表之队列,Python3实现—