# Title: Dijkstra's Algorithm for finding single source shortest path from scratch# Author: Shubham Malik# References: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithmfrom __future__ import print_functionimport mathimport sys# For storing the vertex set to retreive node with the lowest distanceclass PriorityQueue:# Based on Min Heapdef __init__(self):self.cur_size = 0self.array = []self.pos = {} # To store the pos of node in arraydef isEmpty(self):return self.cur_size == 0def min_heapify(self, idx):lc = self.left(idx)rc = self.right(idx)if lc < self.cur_size and self.array(lc)[0] < self.array(idx)[0]:smallest = lcelse:smallest = idxif rc < self.cur_size and self.array(rc)[0] < self.array(smallest)[0]:smallest = rcif smallest != idx:self.swap(idx, smallest)self.min_heapify(smallest)def insert(self, tup):# Inserts a node into the Priority Queueself.pos[tup[1]] = self.cur_sizeself.cur_size += 1self.array.append((sys.maxsize, tup[1]))self.decrease_key((sys.maxsize, tup[1]), tup[0])def extract_min(self):# Removes and returns the min element at top of priority queuemin_node = self.array[0][1]self.array[0] = self.array[self.cur_size - 1]self.cur_size -= 1self.min_heapify(1)del self.pos[min_node]return min_nodedef left(self, i):# returns the index of left childreturn 2 * i + 1def right(self, i):# returns the index of right childreturn 2 * i + 2def par(self, i):# returns the index of parentreturn math.floor(i / 2)def swap(self, i, j):# swaps array elements at indices i and j# update the pos{}self.pos[self.array[i][1]] = jself.pos[self.array[j][1]] = itemp = self.array[i]self.array[i] = self.array[j]self.array[j] = tempdef decrease_key(self, tup, new_d):idx = self.pos[tup[1]]# assuming the new_d is atmost old_dself.array[idx] = (new_d, tup[1])while idx > 0 and self.array[self.par(idx)][0] > self.array[idx][0]:self.swap(idx, self.par(idx))idx = self.par(idx)class Graph:def __init__(self, num):self.adjList = {} # To store graph: u -> (v,w)self.num_nodes = num # Number of nodes in graph# To store the distance from source vertexself.dist = [0] * self.num_nodesself.par = [-1] * self.num_nodes # To store the pathdef add_edge(self, u, v, w):# Edge going from node u to v and v to u with weight w# u (w)-> v, v (w) -> u# Check if u already in graphif u in self.adjList.keys():self.adjList[u].append((v, w))else:self.adjList[u] = [(v, w)]# Assuming undirected graphif v in self.adjList.keys():self.adjList[v].append((u, w))else:self.adjList[v] = [(u, w)]def show_graph(self):# u -> v(w)for u in self.adjList:print(u, '->', ' -> '.join(str("{}({})".format(v, w))for v, w in self.adjList[u]))def dijkstra(self, src):# Flush old junk values in par[]self.par = [-1] * self.num_nodes# src is the source nodeself.dist[src] = 0Q = PriorityQueue()Q.insert((0, src)) # (dist from src, node)for u in self.adjList.keys():if u != src:self.dist[u] = sys.maxsize # Infinityself.par[u] = -1while not Q.isEmpty():u = Q.extract_min() # Returns node with the min dist from source# Update the distance of all the neighbours of u and# if their prev dist was INFINITY then push them in Qfor v, w in self.adjList[u]:new_dist = self.dist[u] + wif self.dist[v] > new_dist:if self.dist[v] == sys.maxsize:Q.insert((new_dist, v))else:Q.decrease_key((self.dist[v], v), new_dist)self.dist[v] = new_distself.par[v] = u# Show the shortest distances from srcself.show_distances(src)def show_distances(self, src):print("Distance from node: {}".format(src))for u in range(self.num_nodes):print('Node {} has distance: {}'.format(u, self.dist[u]))def show_path(self, src, dest):# To show the shortest path from src to dest# WARNING: Use it *after* calling dijkstrapath = []cost = 0temp = dest# Backtracking from dest to srcwhile self.par[temp] != -1:path.append(temp)if temp != src:for v, w in self.adjList[temp]:if v == self.par[temp]:cost += wbreaktemp = self.par[temp]path.append(src)path.reverse()print('----Path to reach {} from {}----'.format(dest, src))for u in path:print('{}'.format(u), end=' ')if u != dest:print('-> ', end='')print('\nTotal cost of path: ', cost)if __name__ == '__main__':graph = Graph(9)graph.add_edge(0, 1, 4)graph.add_edge(0, 7, 8)graph.add_edge(1, 2, 8)graph.add_edge(1, 7, 11)graph.add_edge(2, 3, 7)graph.add_edge(2, 8, 2)graph.add_edge(2, 5, 4)graph.add_edge(3, 4, 9)graph.add_edge(3, 5, 14)graph.add_edge(4, 5, 10)graph.add_edge(5, 6, 2)graph.add_edge(6, 7, 1)graph.add_edge(6, 8, 6)graph.add_edge(7, 8, 7)graph.show_graph()graph.dijkstra(0)graph.show_path(0, 4)# OUTPUT# 0 -> 1(4) -> 7(8)# 1 -> 0(4) -> 2(8) -> 7(11)# 7 -> 0(8) -> 1(11) -> 6(1) -> 8(7)# 2 -> 1(8) -> 3(7) -> 8(2) -> 5(4)# 3 -> 2(7) -> 4(9) -> 5(14)# 8 -> 2(2) -> 6(6) -> 7(7)# 5 -> 2(4) -> 3(14) -> 4(10) -> 6(2)# 4 -> 3(9) -> 5(10)# 6 -> 5(2) -> 7(1) -> 8(6)# Distance from node: 0# Node 0 has distance: 0# Node 1 has distance: 4# Node 2 has distance: 12# Node 3 has distance: 19# Node 4 has distance: 21# Node 5 has distance: 11# Node 6 has distance: 9# Node 7 has distance: 8# Node 8 has distance: 14# ----Path to reach 4 from 0----# 0 -> 7 -> 6 -> 5 -> 4# Total cost of path: 21
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。