Skip to content

Commit 03d3435

Browse files
chidi-godwingnccclauss
authored
Graph list patch (#4113)
* new implementation for adjacency list graph * add example code for undirected graph * reduce length to 88 columns max to fix build errors7 * fix pre commit issues * replace print_list method with __str__ * return object in add_edge method to enable fluent syntax * improve class docstring and include doctests * add end of file line * fix pre-commit issues * remove __str__ method * trigger build * Update graph_list.py * Update graph_list.py Co-authored-by: gnc <[email protected]> Co-authored-by: Christian Clauss <[email protected]>
1 parent 677d48d commit 03d3435

File tree

1 file changed

+134
-35
lines changed

1 file changed

+134
-35
lines changed

Diff for: graphs/graph_list.py

+134-35
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,143 @@
1-
#!/usr/bin/python
1+
#!/usr/bin/env python3
22

3-
# Author: OMKAR PATHAK
3+
# Author: OMKAR PATHAK, Nwachukwu Chidiebere
44

5-
# We can use Python's dictionary for constructing the graph.
5+
# Use a Python dictionary to construct the graph.
66

7+
from pprint import pformat
78

8-
class AdjacencyList:
9-
def __init__(self):
10-
self.adj_list = {}
119

12-
def add_edge(self, from_vertex: int, to_vertex: int) -> None:
13-
# check if vertex is already present
14-
if from_vertex in self.adj_list:
15-
self.adj_list[from_vertex].append(to_vertex)
16-
else:
17-
self.adj_list[from_vertex] = [to_vertex]
10+
class GraphAdjacencyList:
11+
"""
12+
Adjacency List type Graph Data Structure that accounts for directed and undirected
13+
Graphs. Initialize graph object indicating whether it's directed or undirected.
1814
19-
def print_list(self) -> None:
20-
for i in self.adj_list:
21-
print((i, "->", " -> ".join([str(j) for j in self.adj_list[i]])))
15+
Directed graph example:
16+
>>> d_graph = GraphAdjacencyList()
17+
>>> d_graph
18+
{}
19+
>>> d_graph.add_edge(0, 1)
20+
{0: [1], 1: []}
21+
>>> d_graph.add_edge(1, 2).add_edge(1, 4).add_edge(1, 5)
22+
{0: [1], 1: [2, 4, 5], 2: [], 4: [], 5: []}
23+
>>> d_graph.add_edge(2, 0).add_edge(2, 6).add_edge(2, 7)
24+
{0: [1], 1: [2, 4, 5], 2: [0, 6, 7], 4: [], 5: [], 6: [], 7: []}
25+
>>> print(d_graph)
26+
{0: [1], 1: [2, 4, 5], 2: [0, 6, 7], 4: [], 5: [], 6: [], 7: []}
27+
>>> print(repr(d_graph))
28+
{0: [1], 1: [2, 4, 5], 2: [0, 6, 7], 4: [], 5: [], 6: [], 7: []}
29+
30+
Undirected graph example:
31+
>>> u_graph = GraphAdjacencyList(directed=False)
32+
>>> u_graph.add_edge(0, 1)
33+
{0: [1], 1: [0]}
34+
>>> u_graph.add_edge(1, 2).add_edge(1, 4).add_edge(1, 5)
35+
{0: [1], 1: [0, 2, 4, 5], 2: [1], 4: [1], 5: [1]}
36+
>>> u_graph.add_edge(2, 0).add_edge(2, 6).add_edge(2, 7)
37+
{0: [1, 2], 1: [0, 2, 4, 5], 2: [1, 0, 6, 7], 4: [1], 5: [1], 6: [2], 7: [2]}
38+
>>> u_graph.add_edge(4, 5)
39+
{0: [1, 2],
40+
1: [0, 2, 4, 5],
41+
2: [1, 0, 6, 7],
42+
4: [1, 5],
43+
5: [1, 4],
44+
6: [2],
45+
7: [2]}
46+
>>> print(u_graph)
47+
{0: [1, 2],
48+
1: [0, 2, 4, 5],
49+
2: [1, 0, 6, 7],
50+
4: [1, 5],
51+
5: [1, 4],
52+
6: [2],
53+
7: [2]}
54+
>>> print(repr(u_graph))
55+
{0: [1, 2],
56+
1: [0, 2, 4, 5],
57+
2: [1, 0, 6, 7],
58+
4: [1, 5],
59+
5: [1, 4],
60+
6: [2],
61+
7: [2]}
62+
"""
63+
64+
def __init__(self, directed: bool = True):
65+
"""
66+
Parameters:
67+
directed: (bool) Indicates if graph is directed or undirected. Default is True.
68+
"""
69+
70+
self.adj_list = {} # dictionary of lists
71+
self.directed = directed
72+
73+
def add_edge(self, source_vertex: int, destination_vertex: int) -> object:
74+
"""
75+
Connects vertices together. Creates and Edge from source vertex to destination
76+
vertex.
77+
Vertices will be created if not found in graph
78+
"""
79+
80+
if not self.directed: # For undirected graphs
81+
# if both source vertex and destination vertex are both present in the
82+
# adjacency list, add destination vertex to source vertex list of adjacent
83+
# vertices and add source vertex to destination vertex list of adjacent
84+
# vertices.
85+
if source_vertex in self.adj_list and destination_vertex in self.adj_list:
86+
self.adj_list[source_vertex].append(destination_vertex)
87+
self.adj_list[destination_vertex].append(source_vertex)
88+
# if only source vertex is present in adjacency list, add destination vertex
89+
# to source vertex list of adjacent vertices, then create a new vertex with
90+
# destination vertex as key and assign a list containing the source vertex
91+
# as it's first adjacent vertex.
92+
elif source_vertex in self.adj_list:
93+
self.adj_list[source_vertex].append(destination_vertex)
94+
self.adj_list[destination_vertex] = [source_vertex]
95+
# if only destination vertex is present in adjacency list, add source vertex
96+
# to destination vertex list of adjacent vertices, then create a new vertex
97+
# with source vertex as key and assign a list containing the source vertex
98+
# as it's first adjacent vertex.
99+
elif destination_vertex in self.adj_list:
100+
self.adj_list[destination_vertex].append(source_vertex)
101+
self.adj_list[source_vertex] = [destination_vertex]
102+
# if both source vertex and destination vertex are not present in adjacency
103+
# list, create a new vertex with source vertex as key and assign a list
104+
# containing the destination vertex as it's first adjacent vertex also
105+
# create a new vertex with destination vertex as key and assign a list
106+
# containing the source vertex as it's first adjacent vertex.
107+
else:
108+
self.adj_list[source_vertex] = [destination_vertex]
109+
self.adj_list[destination_vertex] = [source_vertex]
110+
else: # For directed graphs
111+
# if both source vertex and destination vertex are present in adjacency
112+
# list, add destination vertex to source vertex list of adjacent vertices.
113+
if source_vertex in self.adj_list and destination_vertex in self.adj_list:
114+
self.adj_list[source_vertex].append(destination_vertex)
115+
# if only source vertex is present in adjacency list, add destination
116+
# vertex to source vertex list of adjacent vertices and create a new vertex
117+
# with destination vertex as key, which has no adjacent vertex
118+
elif source_vertex in self.adj_list:
119+
self.adj_list[source_vertex].append(destination_vertex)
120+
self.adj_list[destination_vertex] = []
121+
# if only destination vertex is present in adjacency list, create a new
122+
# vertex with source vertex as key and assign a list containing destination
123+
# vertex as first adjacent vertex
124+
elif destination_vertex in self.adj_list:
125+
self.adj_list[source_vertex] = [destination_vertex]
126+
# if both source vertex and destination vertex are not present in adjacency
127+
# list, create a new vertex with source vertex as key and a list containing
128+
# destination vertex as it's first adjacent vertex. Then create a new vertex
129+
# with destination vertex as key, which has no adjacent vertex
130+
else:
131+
self.adj_list[source_vertex] = [destination_vertex]
132+
self.adj_list[destination_vertex] = []
133+
134+
return self
135+
136+
def __repr__(self) -> str:
137+
return pformat(self.adj_list)
22138

23139

24140
if __name__ == "__main__":
25-
al = AdjacencyList()
26-
al.add_edge(0, 1)
27-
al.add_edge(0, 4)
28-
al.add_edge(4, 1)
29-
al.add_edge(4, 3)
30-
al.add_edge(1, 0)
31-
al.add_edge(1, 4)
32-
al.add_edge(1, 3)
33-
al.add_edge(1, 2)
34-
al.add_edge(2, 3)
35-
al.add_edge(3, 4)
36-
37-
al.print_list()
38-
39-
# OUTPUT:
40-
# 0 -> 1 -> 4
41-
# 1 -> 0 -> 4 -> 3 -> 2
42-
# 2 -> 3
43-
# 3 -> 4
44-
# 4 -> 1 -> 3
141+
import doctest
142+
143+
doctest.testmod()

0 commit comments

Comments
 (0)