Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 36a1004

Browse files
committed
Initial implementation
1 parent 08e8ca2 commit 36a1004

File tree

7 files changed

+527
-0
lines changed

7 files changed

+527
-0
lines changed

‎Classes/README.md

Whitespace-only changes.
766 Bytes
Binary file not shown.

‎Classes/graph_adj_list_dict.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
from node import Node
2+
from queue import Queue
3+
4+
class Graph:
5+
###################################
6+
# Constructor
7+
###################################
8+
def __init__(self, num_of_nodes, directed=True):
9+
self.m_num_of_nodes = num_of_nodes
10+
# self.m_nodes = range(self.m_num_of_nodes)
11+
self.m_nodes = set()
12+
13+
self.m_directed = directed
14+
15+
# self.m_graph = {node: set() for node in self.m_nodes}
16+
self.m_graph = {}
17+
18+
###################################
19+
# Add edge to a graph
20+
###################################
21+
def add_edge(self, node1_name, node2_name, weight=1):
22+
node1 = Node(node1_name)
23+
node2 = Node(node2_name)
24+
if (node1 not in self.m_nodes):
25+
node1_id = len(self.m_nodes)
26+
node1.change_id(node1_id)
27+
self.m_nodes.add(node1)
28+
self.m_graph[node1_name] = set()
29+
30+
if (node2 not in self.m_nodes):
31+
node2_id = len(self.m_nodes)
32+
node2.change_id(node2_id)
33+
self.m_nodes.add(node2)
34+
self.m_graph[node2_name] = set()
35+
print("Adding ", node1_name, node2_name)
36+
self.m_graph[node1_name].add((node2, weight))
37+
38+
if not self.m_directed:
39+
self.m_graph[node2_name].add((node1, weight))
40+
41+
42+
###################################
43+
# Load a graph from a dictionary
44+
# definig an adjacency list
45+
# For exaple:
46+
# adjacency_list = {
47+
# 'A': [('B', 1), ('C', 3), ('D', 7)],
48+
# 'B': [('D', 5)],
49+
# 'C': [('D', 12)]
50+
# }
51+
###################################
52+
def load_from_dict(self, dict):
53+
if len(dict) > self.m_num_of_nodes:
54+
raise ValueError("Number of nodes in the dictionary must be " + str(self.m_num_of_nodes))
55+
for node1 in dict.keys():
56+
for (node2, weight) in dict[node1]:
57+
self.add_edge(node1, node2, weight)
58+
59+
###################################
60+
# Load a graph from a list of edges
61+
# For example:
62+
# edge_list = [
63+
# [0, 0, 25],
64+
# [0, 1, 5],
65+
# [0, 2, 3],
66+
# [1, 3, 1],
67+
# [1, 4, 15],
68+
# [4, 2, 7],
69+
# [4, 3, 11]
70+
# ]
71+
###################################
72+
def load_from_edge_list(self, edge_list):
73+
num_of_edges = len(edge_list)
74+
for i in range(num_of_edges):
75+
node1 = edge_list[i][0]
76+
node2 = edge_list[i][1]
77+
weight = edge_list[i][2]
78+
self.add_edge(node1, node2, weight)
79+
80+
81+
###################################
82+
# Print a graph representation
83+
###################################
84+
def __str__(self):
85+
out = ""
86+
for key in self.m_graph.keys():
87+
out += "node " + str(key) + ": " + str(self.m_graph[key]) + "\n"
88+
return out
89+
90+
###################################
91+
# DFS Search
92+
###################################
93+
def dfs(self, start, target, path = [], visited = set()):
94+
path.append(start)
95+
visited.add(start)
96+
if start == target:
97+
return path
98+
for (neighbour, weight) in self.m_graph[start]:
99+
if neighbour not in visited:
100+
result = self.dfs(neighbour, target, path, visited)
101+
if result is not None:
102+
return result
103+
path.pop()
104+
return None
105+
106+
###################################
107+
# BFS Search
108+
###################################
109+
def bfs(self, start_node, target_node):
110+
# Set of visited nodes to prevent loops
111+
visited = set()
112+
queue = Queue()
113+
114+
# Add the start_node to the queue and visited list
115+
queue.put(start_node)
116+
visited.add(start_node)
117+
118+
# start_node has not parents
119+
parent = dict()
120+
parent[start_node] = None
121+
122+
# Perform step 3
123+
path_found = False
124+
while not queue.empty():
125+
current_node = queue.get()
126+
if current_node == target_node:
127+
path_found = True
128+
break
129+
130+
for (next_node, weight) in self.m_graph[current_node]:
131+
if next_node not in visited:
132+
queue.put(next_node)
133+
parent[next_node] = current_node
134+
visited.add(next_node)
135+
136+
# Path reconstruction
137+
path = []
138+
if path_found:
139+
path.append(target_node)
140+
while parent[target_node] is not None:
141+
path.append(parent[target_node])
142+
target_node = parent[target_node]
143+
path.reverse()
144+
return path
145+
146+
###################################
147+
# BFS Traversal
148+
###################################
149+
def bfs_traversal(self, start_node):
150+
visited = set()
151+
queue = Queue()
152+
queue.put(start_node)
153+
visited.add(start_node)
154+
155+
while not queue.empty():
156+
current_node = queue.get()
157+
if current_node:
158+
print(current_node, end = " ")
159+
for (next_node, weight) in self.m_graph[current_node]:
160+
if next_node not in visited:
161+
queue.put(next_node)
162+
visited.add(next_node)
163+
164+
g = Graph(5)
165+
adjacency_list = {
166+
'A': [('B', 1), ('C', 3), ('D', 7)],
167+
'B': [('D', 5)],
168+
'C': [('D', 12)]
169+
}
170+
edge_list = [
171+
[0, 0, 25],
172+
[0, 1, 5],
173+
[0, 2, 3],
174+
[1, 3, 1],
175+
[1, 4, 15],
176+
[4, 2, 7],
177+
[4, 3, 11]
178+
]
179+
# g.load_from_dict(adjacency_list)
180+
g.load_from_edge_list(edge_list)
181+
print(g)
182+

‎Classes/graph_adj_list_linked_list.py

Whitespace-only changes.

‎Classes/graph_adj_matrix.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
class Graph:
2+
###################################
3+
# Constructor
4+
###################################
5+
def __init__(self, num_of_nodes, directed=True):
6+
self.m_num_of_nodes = num_of_nodes
7+
self.m_directed = directed
8+
9+
# Different representations of a graph
10+
# i.e. adjacency matrix
11+
self.m_graph = [[0 for column in range(num_of_nodes)]
12+
for row in range(num_of_nodes)]
13+
14+
###################################
15+
# Assert node names
16+
###################################
17+
def check_node_names(self, name1, name2):
18+
num_of_nodes = self.m_num_of_nodes
19+
node1_name = str(name1)
20+
node2_name = str(name2)
21+
if (not (node1_name.isdigit() and node2_name.isdigit())):
22+
raise TypeError("Node names must be integer values")
23+
if (name1<0 or name1>=num_of_nodes or name2<0 or name2>=num_of_nodes):
24+
raise ValueError("Node names must be from 0 to " + str(num_of_nodes-1))
25+
26+
###################################
27+
# Add edge to a graph
28+
###################################
29+
def add_edge(self, node1, node2, weight=1):
30+
self.check_node_names(node1, node2)
31+
self.m_graph[node1][node2] = weight
32+
33+
if not self.m_directed:
34+
self.m_graph[node2][node1] = weight
35+
36+
###################################
37+
# Print a graph representation
38+
###################################
39+
def __str__(self):
40+
out = ""
41+
for i in range(self.m_num_of_nodes):
42+
out += str(self.m_graph[i]) + "\n"
43+
return out
44+
45+
###################################
46+
# Prims's MST Algorithm
47+
###################################
48+
def prims_mst(self):
49+
# Defining a really big number:
50+
postitive_inf = float('inf')
51+
52+
# This is a list showing which nodes are already selected
53+
# so we don't pick the same node twice and we can actually know when stop looking
54+
selected_nodes = [False for vertex in range(self.m_num_of_nodes)]
55+
56+
# Matrix of the resulting MST
57+
result = [[0 for column in range(self.m_num_of_nodes)]
58+
for row in range(self.m_num_of_nodes)]
59+
60+
indx = 0
61+
for i in range(self.m_num_of_nodes):
62+
print(self.m_graph[i])
63+
64+
print(selected_nodes)
65+
66+
# While there are nodes that are not included in the MST, keep looking:
67+
while(False in selected_nodes):
68+
# We use the big number we created before as the possible minimum weight
69+
minimum = postitive_inf
70+
71+
# The starting node
72+
start = 0
73+
74+
# The ending node
75+
end = 0
76+
77+
for i in range(self.m_num_of_nodes):
78+
# If the node is part of the MST, look its relationships
79+
if selected_nodes[i]:
80+
for j in range(self.m_num_of_nodes):
81+
# If the analyzed node have a path to the ending node AND its not included in the MST (to avoid cycles)
82+
if (not selected_nodes[j] and self.m_graph[i][j]>0):
83+
# If the weight path analized is less than the minimum of the MST
84+
if self.m_graph[i][j] < minimum:
85+
# Defines the new minimum weight, the starting vertex and the ending vertex
86+
minimum = self.m_graph[i][j]
87+
start, end = i, j
88+
89+
# Since we added the ending vertex to the MST, it's already selected:
90+
selected_nodes[end] = True
91+
92+
93+
# Filling the MST Adjacency Matrix fields:
94+
result[start][end] = minimum
95+
96+
if minimum == postitive_inf:
97+
result[start][end] = 0
98+
99+
print("(%d.) %d - %d: %d" % (indx, start, end, result[start][end]))
100+
indx += 1
101+
102+
result[end][start] = result[start][end]
103+
104+
# Print the resulting MST
105+
# for node1, node2, weight in result:
106+
for i in range(len(result)):
107+
for j in range(0+i, len(result)):
108+
if result[i][j] != 0:
109+
print("%d - %d: %d" % (i, j, result[i][j]))
110+
111+
112+
graph = Graph(5)
113+
114+
graph.add_edge(0, 0, 25)
115+
graph.add_edge(0, 1, 5)
116+
graph.add_edge(0, 2, 3)
117+
graph.add_edge(1, 3, 1)
118+
graph.add_edge(1, 4, 15)
119+
graph.add_edge(4, 2, 7)
120+
graph.add_edge(4, 3, 11)
121+
122+
print(graph)
123+
graph.prims_mst()
124+
125+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /