Graphs can be represented as edge lists, adjacency lists, or adjacency matrices. The choice depends on graph density and which operations matter most. Adjacency lists are the default for sparse graphs; matrices for dense graphs needing O(1) edge checks.
classGraph:def__init__(self):self.adj_list={}# vertex -> list of neighborsdefadd_vertex(self,u):ifunotinself.adj_list:self.adj_list[u]=[]defadd_edge(self,u,v):# directedifuinself.adj_listandvinself.adj_list:self.adj_list[u].append(v)defadd_edge_undirected(self,u,v):ifuinself.adj_listandvinself.adj_list:self.adj_list[u].append(v)self.adj_list[v].append(u)defadd_edge_weighted(self,u,v,w):# directed weightedifuinself.adj_listandvinself.adj_list:self.adj_list[u].append((v,w))defremove_vertex(self,u):ifuinself.adj_list:delself.adj_list[u]forvinself.adj_list:ifuinself.adj_list[v]:self.adj_list[v].remove(u)defcheck_edge(self,u,v):returnuinself.adj_listandvinself.adj_list[u]defbuild(self,vertices,edges):foruinvertices:self.add_vertex(u)foru,vinedges:self.add_edge(u,v)
Use set instead of list for O(1) edge existence check at the cost of extra memory.