-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGraph Traversal.py
More file actions
197 lines (158 loc) · 6.46 KB
/
Graph Traversal.py
File metadata and controls
197 lines (158 loc) · 6.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
class Node(object):
def __init__(self, value):
self.value = value
self.edges = []
self.visited = False
class Edge(object):
def __init__(self, value, node_from, node_to):
self.value = value
self.node_from = node_from
self.node_to = node_to
class Graph(object):
def __init__(self, nodes=None, edges=None):
self.nodes = nodes or []
self.edges = edges or []
self.node_names = []
self._node_map = {}
def set_node_names(self, names):
self.node_names = list(names)
def insert_node(self, new_node_val):
"Insert a new node with value new_node_val"
new_node = Node(new_node_val)
self.nodes.append(new_node)
self._node_map[new_node_val] = new_node
return new_node
def insert_edge(self, new_edge_val, node_from_val, node_to_val):
"Insert a new edge, creating new nodes if necessary"
nodes = {node_from_val: None, node_to_val: None}
for node in self.nodes:
if node.value in nodes:
nodes[node.value] = node
if all(nodes.values()):
break
for node_val in nodes:
nodes[node_val] = nodes[node_val] or self.insert_node(node_val)
node_from = nodes[node_from_val]
node_to = nodes[node_to_val]
new_edge = Edge(new_edge_val, node_from, node_to)
node_from.edges.append(new_edge)
node_to.edges.append(new_edge)
self.edges.append(new_edge)
def get_edge_list(self):
return [(e.value, e.node_from.value, e.node_to.value)
for e in self.edges]
def get_edge_list_names(self):
return [(edge.value,
self.node_names[edge.node_from.value],
self.node_names[edge.node_to.value])
for edge in self.edges]
def get_adjacency_list(self):
max_index = self.find_max_index()
adjacency_list = [[] for _ in range(max_index)]
for edg in self.edges:
from_value, to_value = edg.node_from.value, edg.node_to.value
adjacency_list[from_value].append((to_value, edg.value))
return [a or None for a in adjacency_list] # replace []'s with None
def get_adjacency_list_names(self):
adjacency_list = self.get_adjacency_list()
def convert_to_names(pair, graph=self):
node_number, value = pair
return (graph.node_names[node_number], value)
def map_conversion(adjacency_list_for_node):
if adjacency_list_for_node is None:
return None
return map(convert_to_names, adjacency_list_for_node)
return [map_conversion(adjacency_list_for_node)
for adjacency_list_for_node in adjacency_list]
def get_adjacency_matrix(self):
max_index = self.find_max_index()
adjacency_matrix = [[0] * (max_index) for _ in range(max_index)]
for edg in self.edges:
from_index, to_index = edg.node_from.value, edg.node_to.value
adjacency_matrix[from_index][to_index] = edg.value
return adjacency_matrix
def find_max_index(self):
if len(self.node_names) > 0:
return len(self.node_names)
max_index = -1
if len(self.nodes):
for node in self.nodes:
if node.value > max_index:
max_index = node.value
return max_index
def find_node(self, node_number):
return self._node_map.get(node_number)
def _clear_visited(self):
for node in self.nodes:
node.visited = False
def dfs_helper(self, start_node):
ret_list = [start_node.value]
start_node.visited = True
edge_out=[]
for edge in start_node.edges:
if edge.node_to.value != start_node.value:
edge_out.append(edge)
for edge in edge_out:
if edge.node_to.visited==False:
ret_list.extend(self.dfs_helper(edge.node_to))
return ret_list
def dfs(self, start_node_num):
self._clear_visited()
start_node = self.find_node(start_node_num)
return self.dfs_helper(start_node)
def dfs_names(self, start_node_num):
return [self.node_names[num] for num in self.dfs(start_node_num)]
def bfs(self, start_node_num):
node = self.find_node(start_node_num)
self._clear_visited()
ret_list = []
queue = [node]
node.visited = True
def enqueue(node, q=queue):
node.visited = True
q.append(node)
while queue:
node = queue.pop(0)
ret_list.append(node.value)
for edge in node.edges:
if edge.node_to.visited==False:
enqueue(edge.node_to,queue)
return ret_list
def bfs_names(self, start_node_num):
return [self.node_names[num] for num in self.bfs(start_node_num)]
graph = Graph()
graph.set_node_names(('Mountain View', # 0
'San Francisco', # 1
'London', # 2
'Shanghai', # 3
'Berlin', # 4
'Sao Paolo', # 5
'Bangalore')) # 6
graph.insert_edge(51, 0, 1) # MV <-> SF
graph.insert_edge(51, 1, 0) # SF <-> MV
graph.insert_edge(9950, 0, 3) # MV <-> Shanghai
graph.insert_edge(9950, 3, 0) # Shanghai <-> MV
graph.insert_edge(10375, 0, 5) # MV <-> Sao Paolo
graph.insert_edge(10375, 5, 0) # Sao Paolo <-> MV
graph.insert_edge(9900, 1, 3) # SF <-> Shanghai
graph.insert_edge(9900, 3, 1) # Shanghai <-> SF
graph.insert_edge(9130, 1, 4) # SF <-> Berlin
graph.insert_edge(9130, 4, 1) # Berlin <-> SF
graph.insert_edge(9217, 2, 3) # London <-> Shanghai
graph.insert_edge(9217, 3, 2) # Shanghai <-> London
graph.insert_edge(932, 2, 4) # London <-> Berlin
graph.insert_edge(932, 4, 2) # Berlin <-> London
graph.insert_edge(9471, 2, 5) # London <-> Sao Paolo
graph.insert_edge(9471, 5, 2) # Sao Paolo <-> London
import pprint
pp = pprint.PrettyPrinter(indent=2)
print ("Edge List")
pp.pprint(graph.get_edge_list_names())
print ("\nAdjacency List")
pp.pprint(graph.get_adjacency_list_names())
print ("\nAdjacency Matrix")
pp.pprint(graph.get_adjacency_matrix())
print ("\nDepth First Search")
pp.pprint(graph.dfs_names(2))
print ("\nBreadth First Search")
pp.pprint(graph.bfs_names(2))