1+ """Graph data structures for graph algorithms."""
2+
3+ from __future__ import annotations
4+
5+ import math
6+ from typing import Any , TypeVar
7+
8+ T = TypeVar ("T" )
9+
10+
111class Vertex :
2- def __init__ (self , value ):
3- self .value = value
12+ """A vertex in a graph with an associated value."""
413
5- def __eq__ (self , other ):
14+ def __init__ (self , value : T ) -> None :
15+ self .value = value
616
17+ def __eq__ (self , other : object ) -> bool :
718 if isinstance (other , Vertex ):
819 return self .value == other .value
9-
1020 return False
1121
12- def __lt__ (self , other ):
13-
22+ def __lt__ (self , other : object ) -> bool :
1423 if not isinstance (other , Vertex ):
1524 raise NotImplementedError
16-
1725 return self .value < other .value
1826
19- def __repr__ (self ):
27+ def __repr__ (self ) -> str :
2028 return str (self .value )
2129
22- def __hash__ (self ):
30+ def __hash__ (self ) -> int :
2331 return hash (self .value )
2432
2533
2634class Edge :
27- def __init__ (self , source , destination , distance ):
35+ """A weighted directed edge connecting two vertices."""
36+
37+ def __init__ (self , source : Vertex , destination : Vertex , distance : float ) -> None :
2838 self .source = source
2939 self .destination = destination
3040 self .distance = distance
3141
32- def __eq__ (self , other ):
33-
42+ def __eq__ (self , other : object ) -> bool :
3443 if isinstance (other , Edge ):
3544 return (
3645 self .source == other .source
3746 and self .destination == other .destination
3847 and self .distance == other .distance
3948 )
40-
4149 return False
4250
43- def __lt__ (self , other ):
44-
51+ def __lt__ (self , other : object ) -> bool :
4552 if not isinstance (other , Edge ):
4653 raise NotImplementedError
47-
4854 return self .distance < other .distance
4955
50- def __repr__ (self ):
56+ def __repr__ (self ) -> str :
5157 return f"({ self .source } , { self .destination } , { self .distance } )"
5258
5359
5460class Graph :
55- def __init__ (self ):
56- self ._adj_dict = dict ()
61+ """A directed weighted graph using adjacency list representation."""
5762
58- def add_edge (self , edge ):
63+ def __init__ (self ) -> None :
64+ self ._adj_dict : dict [Vertex , list [Edge ]] = {}
5965
66+ def add_edge (self , edge : Edge ) -> None :
67+ """Add an edge to the graph."""
6068 if edge .source in self ._adj_dict :
6169 self ._adj_dict [edge .source ].append (edge )
62-
6370 else :
6471 self ._adj_dict [edge .source ] = [edge ]
6572
6673 if edge .destination not in self ._adj_dict :
67- self ._adj_dict [edge .destination ] = list ()
74+ self ._adj_dict [edge .destination ] = []
6875
69- def add_vertex (self , vertex ):
76+ def add_vertex (self , vertex : Vertex ) -> None :
77+ """Add a vertex to the graph."""
7078 if vertex not in self ._adj_dict :
71- self ._adj_dict [vertex ] = list ()
79+ self ._adj_dict [vertex ] = []
7280
73- def vertices (self ):
81+ def vertices (self ) -> list [Vertex ]:
82+ """Return a list of all vertices in the graph."""
7483 return list (self ._adj_dict .keys ())
7584
76- def edges (self ):
85+ def edges (self ) -> list [Edge ]:
86+ """Return a list of all edges in the graph."""
7787 return [elem for array in self ._adj_dict .values () for elem in array if array ]
7888
79- def edges_from_vertex (self , vertex ):
89+ def edges_from_vertex (self , vertex : Vertex ) -> list [Edge ]:
90+ """Return all edges originating from the given vertex."""
8091 self ._assert_graph_contains_vertex (vertex )
8192 return self ._adj_dict [vertex ]
8293
83- def contains (self , vertex ):
94+ def contains (self , vertex : Vertex ) -> bool :
95+ """Check if the graph contains the given vertex."""
8496 return vertex in self ._adj_dict
8597
86- def connected (self , vertex_a , vertex_b ):
98+ def connected (self , vertex_a : Vertex , vertex_b : Vertex ) -> bool :
99+ """Check if two vertices are directly connected by an edge."""
87100 self ._assert_graph_contains_vertex (vertex_a )
88101 self ._assert_graph_contains_vertex (vertex_b )
89102
@@ -97,23 +110,23 @@ def connected(self, vertex_a, vertex_b):
97110
98111 return False
99112
100- def empty (self ):
113+ def empty (self ) -> bool :
114+ """Check if the graph has no vertices."""
101115 return len (self ._adj_dict ) == 0
102116
103- def size (self ):
117+ def size (self ) -> int :
118+ """Return the number of vertices in the graph."""
104119 return len (self ._adj_dict )
105120
106- def __repr__ (self ):
107-
121+ def __repr__ (self ) -> str :
108122 result = ""
109123 for vertex , edges in self ._adj_dict .items ():
110124 result += f"{ vertex } —> "
111125 for edge in edges :
112- result += edge
126+ result += str ( edge )
113127 result += "\n "
114-
115128 return result
116129
117- def _assert_graph_contains_vertex (self , vertex ) :
130+ def _assert_graph_contains_vertex (self , vertex : Vertex ) -> None :
118131 if vertex not in self ._adj_dict :
119- raise KeyError (f"Graph doesn't containt the { vertex } vertex!" )
132+ raise KeyError (f"Graph doesn't contain the { vertex } vertex!" )
0 commit comments