Skip to content

Commit 4f10624

Browse files
committed
Undirected graph class with adjacency matrix. DFS (recursive), DFS (iterative), BFS.
1 parent 8017205 commit 4f10624

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

graphs/undirected_graph_matrix.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import queue
2+
3+
4+
class UndirectedGraph(object):
5+
"""
6+
Undirected Graph, with graph represented as an adjacency matrix
7+
"""
8+
9+
def __init__(self, vertices):
10+
self.adjacency_matrix = []
11+
for i in range(vertices):
12+
self.adjacency_matrix.append([0] * vertices)
13+
14+
def add_edge(self, source, destination):
15+
"""
16+
Adds an edge defined by vertices from source to destination
17+
then destination to source in matrix
18+
:param source:
19+
:param destination:
20+
:return:
21+
"""
22+
self.adjacency_matrix[source][destination] = 1
23+
self.adjacency_matrix[destination][source] = 1
24+
25+
def get_vertex(self):
26+
"""
27+
Generator for returning the next vertex from the adjacency list
28+
:return:
29+
"""
30+
for v, __ in enumerate(self.adjacency_matrix):
31+
yield v
32+
33+
def get_neighbor(self, vertex):
34+
"""
35+
Generator for returning the next vertex adjacent to the given vertex
36+
:param vertex:
37+
:return:
38+
"""
39+
for i, flag in enumerate(self.adjacency_matrix[vertex]):
40+
if flag == 1:
41+
yield i
42+
43+
def dfs_recursive(self):
44+
"""
45+
Computes the parents for each vertex as determined through depth-first-search
46+
(though not too meaningful in an undirected weightless graph)
47+
:return: parents for each vertex
48+
:rtype: dict
49+
"""
50+
parents = {}
51+
52+
self.dfs_util(0, parents)
53+
54+
return parents
55+
56+
def dfs_util(self, vertex, parents):
57+
for u in self.get_neighbor(vertex):
58+
if u not in parents:
59+
parents[u] = vertex
60+
self.dfs_util(u, parents)
61+
62+
def dfs_iterative(self):
63+
"""
64+
Computes the parents for each vertex as determined through depth-first-search
65+
(though not too meaningful in an undirected weightless graph)
66+
:return: parents for each vertex
67+
:rtype: dict
68+
"""
69+
parents = {}
70+
to_visit = [0]
71+
72+
while to_visit:
73+
v = to_visit.pop()
74+
75+
for neighbor in self.get_neighbor(v):
76+
if neighbor not in parents:
77+
parents[neighbor] = v
78+
to_visit.append(neighbor)
79+
80+
return parents
81+
82+
def bfs(self):
83+
"""
84+
Computes the the parents for each vertex as determined through breadth-first search
85+
:return: parents for each vertex
86+
:rtype: dict
87+
"""
88+
parents = {}
89+
to_visit = queue.Queue()
90+
to_visit.put(0)
91+
92+
while not to_visit.empty():
93+
v = to_visit.get()
94+
95+
for neighbor in self.get_neighbor(v):
96+
if neighbor not in parents:
97+
parents[neighbor] = v
98+
to_visit.put(neighbor)
99+
100+
return parents
101+
102+
103+
def get_test_graph_1():
104+
udg = UndirectedGraph(9)
105+
udg.add_edge(0, 1)
106+
udg.add_edge(1, 2)
107+
udg.add_edge(2, 3)
108+
udg.add_edge(1, 7)
109+
udg.add_edge(3, 7)
110+
udg.add_edge(7, 8)
111+
udg.add_edge(3, 4)
112+
udg.add_edge(3, 5)
113+
udg.add_edge(4, 5)
114+
udg.add_edge(5, 6)
115+
udg.add_edge(6, 7)
116+
udg.add_edge(6, 8)
117+
118+
return udg
119+
120+
121+
def test_dfs_recursive():
122+
udg = get_test_graph_1()
123+
p1 = udg.dfs_recursive()
124+
assert(p1 == {0: 1, 1: 0, 2: 1, 3: 2, 4: 3, 5: 4, 6: 5, 7: 6, 8: 7})
125+
126+
127+
def test_dfs_iterative():
128+
udg = get_test_graph_1()
129+
p1 = udg.dfs_iterative()
130+
assert(p1 == {0: 1, 1: 0, 2: 1, 3: 7, 4: 5, 5: 6, 6: 7, 7: 1, 8: 7})
131+
132+
133+
def test_bfs():
134+
udg = get_test_graph_1()
135+
p1 = udg.bfs()
136+
assert(p1 == {0: 1, 1: 0, 2: 1, 3: 2, 4: 3, 5: 3, 6: 7, 7: 1, 8: 7})
137+
138+
139+
def main():
140+
test_dfs_recursive()
141+
test_dfs_iterative()
142+
test_bfs()
143+
144+
print("Tests complete.")
145+
146+
if __name__ == "__main__":
147+
main()

0 commit comments

Comments
 (0)