Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dijkstra visualizer added #562

Merged
merged 1 commit into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions Algorithms_and_Data_Structures/Dijkstra/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import networkx as nx
import matplotlib.pyplot as plt

# function to create graph
def graph_create():
G = nx.Graph()
nodes_num = int(input("Enter the number of nodes: "))
for i in range(nodes_num):
nodes_name = input(f"Enter the name of node {i+1} : ")

edges = int(input("Enter the number of edges: "))
for i in range(edges):
edge_name = input(f"Enter edge {i+1} : (format: source, destination, value): ")
source, destination, weight = edge_name.split()
G.add_edge(source, destination, weight = int(weight))

return G

# dijkstra algorithm implementation
def dijkstra(graph, start):
distances = {node: float("inf") for node in graph.nodes} #dictionary to store shortest distances
distances[start] = 0
paths = {node: [] for node in graph.nodes} #dictionary to store shortest paths
visited = set()

while len(visited) < len(graph.nodes): #loop till all nodes are visited
not_visited = {node: distances[node] for node in graph.nodes if node not in visited} #dictionary contains distances of unvisited nodes
min_node = min(not_visited, key=not_visited.get) # to get node with minimum distance from start node
visited.add(min_node)

for neighbor, weight in graph[min_node].items():
# If the distance to the neighbor through the current node is less than the previously known shortest distance to the neighbor
if distances[min_node] + weight["weight"] < distances[neighbor]:
# Update the shortest distance and path to the neighbor
distances[neighbor] = distances[min_node] + weight["weight"]
paths[neighbor] = paths[min_node] + [min_node]

# After visiting all nodes, finalize the shortest paths by adding the destination node to each path

paths = {node: path + [node] for node, path in paths.items() if path}

return distances, paths

def visualise_dijkstra(graph, start):
if start not in graph.nodes:
print("Start node not found in graph")
return

distances, paths = dijkstra(graph, start)
pos = nx.spring_layout(graph)
plt.get_current_fig_manager().window.title("Dijkstra Algorithm Visualiser")
nx.draw(graph, pos, with_labels = True, node_color = "lightblue", edgecolors="black", node_size = 500, font_size = 15, font_weight = "bold")
labels = nx.get_edge_attributes(graph, "weight")
nx.draw_networkx_edge_labels(graph, pos, edge_labels = labels, font_size = 8)

plt.title("Dijkstra's Algorithm Visualisation")
print("Shortest distances from the start node:")
for node, distance in distances.items():
print(f"{node}: {distance}")

print("Shortest paths from the start node:")
for node, path in paths.items():
print(f"{node}: {' -> '.join(path)}")

plt.show()

if __name__ == "__main__":
user_graph = graph_create()
start_node = input("Enter the start node: ")
visualise_dijkstra(user_graph, start_node)





41 changes: 41 additions & 0 deletions Algorithms_and_Data_Structures/Dijkstra/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import unittest
from main import dijkstra

class DijkstraTestCase(unittest.TestCase):
def test_shortest_path(self):
graph = {
'A': {'B': {'weight': 5}, 'C': {'weight': 3}},
'B': {'A': {'weight': 5}, 'C': {'weight': 2}, 'D': {'weight': 1}},
'C': {'A': {'weight': 3}, 'B': {'weight': 2}, 'D': {'weight': 4}, 'E': {'weight': 6}},
'D': {'B': {'weight': 1}, 'C': {'weight': 4}, 'E': {'weight': 2}},
'E': {'C': {'weight': 6}, 'D': {'weight': 2}}
}
start_node = 'A'
expected_distances = {'A': 0, 'B': 3, 'C': 3, 'D': 4, 'E': 6}
expected_paths = {'A': ['A'], 'B': ['A', 'B'], 'C': ['A', 'C'], 'D': ['A', 'B', 'D'], 'E': ['A', 'B', 'D', 'E']}

distances, paths = dijkstra(graph, start_node)

self.assertEqual(distances, expected_distances)
self.assertEqual(paths, expected_paths)

def test_disconnected_graph(self):
graph = {
'A': {'B': {'weight': 5}, 'C': {'weight': 3}},
'B': {'A': {'weight': 5}, 'C': {'weight': 2}, 'D': {'weight': 1}},
'C': {'A': {'weight': 3}, 'B': {'weight': 2}, 'D': {'weight': 4}, 'E': {'weight': 6}},
'D': {'B': {'weight': 1}, 'C': {'weight': 4}, 'E': {'weight': 2}},
'E': {'C': {'weight': 6}, 'D': {'weight': 2}},
'F': {} # Disconnected node
}
start_node = 'A'
expected_distances = {'A': 0, 'B': 3, 'C': 3, 'D': 4, 'E': 6}
expected_paths = {'A': ['A'], 'B': ['A', 'B'], 'C': ['A', 'C'], 'D': ['A', 'B', 'D'], 'E': ['A', 'B', 'D', 'E']}

distances, paths = dijkstra(graph, start_node)

self.assertEqual(distances, expected_distances)
self.assertEqual(paths, expected_paths)

if __name__ == '__main__':
unittest.main()