Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 26c0848

Browse files
authoredMar 24, 2020
Added sequential Prim's algorithm (#210)
* Sequential version of Prim's minimum spanning tree algorithm has been added. * `BinomialHeap` now uses `list` instead of `DynamicOneDimensionalArray` for maintaining list of `BinomialTree` objects.
1 parent a5a7ad9 commit 26c0848

File tree

4 files changed

+43
-14
lines changed

4 files changed

+43
-14
lines changed
 

‎pydatastructs/graphs/algorithms.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from collections import deque as Queue
66
from concurrent.futures import ThreadPoolExecutor
77
from pydatastructs.utils import GraphEdge
8-
from pydatastructs.miscellaneous_data_structures import DisjointSetForest
8+
from pydatastructs.miscellaneous_data_structures import (
9+
DisjointSetForest, PriorityQueue)
910
from pydatastructs.graphs.graph import Graph
1011
from pydatastructs.linear_data_structures.algorithms import merge_sort_parallel
1112

@@ -215,12 +216,36 @@ def _minimum_spanning_tree_kruskal_adjacency_list(graph):
215216
u, v = edge.source.name, edge.target.name
216217
if dsf.find_root(u) is not dsf.find_root(v):
217218
mst.add_edge(u, v, edge.value)
219+
mst.add_edge(v, u, edge.value)
218220
dsf.union(u, v)
219221
return mst
220222

221223
_minimum_spanning_tree_kruskal_adjacency_matrix = \
222224
_minimum_spanning_tree_kruskal_adjacency_list
223225

226+
def _minimum_spanning_tree_prim_adjacency_list(graph):
227+
q = PriorityQueue(implementation='binomial_heap')
228+
e = dict()
229+
mst = Graph(implementation='adjacency_list')
230+
q.push(next(iter(graph.vertices)), 0)
231+
while not q.is_empty:
232+
v = q.pop()
233+
if not hasattr(mst, v):
234+
mst.add_vertex(graph.__getattribute__(v))
235+
if e.get(v, None) is not None:
236+
edge = e[v]
237+
mst.add_vertex(edge.target)
238+
mst.add_edge(edge.source.name, edge.target.name, edge.value)
239+
mst.add_edge(edge.target.name, edge.source.name, edge.value)
240+
for w_node in graph.neighbors(v):
241+
w = w_node.name
242+
vw = graph.edge_weights[v + '_' + w]
243+
q.push(w, vw.value)
244+
if e.get(w, None) is None or \
245+
e[w].value > vw.value:
246+
e[w] = vw
247+
return mst
248+
224249
def minimum_spanning_tree(graph, algorithm):
225250
"""
226251
Computes a minimum spanning tree for the given
@@ -239,6 +264,7 @@ def minimum_spanning_tree(graph, algorithm):
239264
supported,
240265
'kruskal' -> Kruskal's algorithm as given in
241266
[1].
267+
'prim' -> Prim's algorithm as given in [2].
242268
243269
Returns
244270
=======
@@ -265,6 +291,7 @@ def minimum_spanning_tree(graph, algorithm):
265291
==========
266292
267293
.. [1] https://en.wikipedia.org/wiki/Kruskal%27s_algorithm
294+
.. [2] https://en.wikipedia.org/wiki/Prim%27s_algorithm
268295
269296
Note
270297
====
@@ -293,6 +320,7 @@ def _minimum_spanning_tree_parallel_kruskal_adjacency_list(graph, num_threads):
293320
u, v = edge.source.name, edge.target.name
294321
if dsf.find_root(u) is not dsf.find_root(v):
295322
mst.add_edge(u, v, edge.value)
323+
mst.add_edge(v, u, edge.value)
296324
dsf.union(u, v)
297325
return mst
298326

‎pydatastructs/graphs/tests/test_algorithms.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,12 +143,13 @@ def _test_minimum_spanning_tree(ds, algorithm):
143143
mst = minimum_spanning_tree(graph, algorithm=algorithm)
144144
expected_mst = [('0_3', 7), ('2_3', 9), ('3_4', 23), ('3_1', 32),
145145
('3_0', 7), ('3_2', 9), ('4_3', 23), ('1_3', 32)]
146-
assert len(expected_mst) == 2*len(mst.edge_weights.items())
146+
assert len(expected_mst) == len(mst.edge_weights.items())
147147
for k, v in mst.edge_weights.items():
148148
assert (k, v.value) in expected_mst
149149

150150
_test_minimum_spanning_tree("List", "kruskal")
151151
_test_minimum_spanning_tree("Matrix", "kruskal")
152+
_test_minimum_spanning_tree("List", "prim")
152153

153154
def test_minimum_spanning_tree_parallel():
154155

@@ -170,7 +171,7 @@ def _test_minimum_spanning_tree_parallel(ds, algorithm):
170171
mst = minimum_spanning_tree_parallel(graph, algorithm, 3)
171172
expected_mst = [('0_3', 7), ('2_3', 9), ('3_4', 23), ('3_1', 32),
172173
('3_0', 7), ('3_2', 9), ('4_3', 23), ('1_3', 32)]
173-
assert len(expected_mst) == 2*len(mst.edge_weights.items())
174+
assert len(expected_mst) == len(mst.edge_weights.items())
174175
for k, v in mst.edge_weights.items():
175176
assert (k, v.value) in expected_mst
176177

‎pydatastructs/trees/heaps.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def __new__(cls, root_list=[]):
356356
raise TypeError("The root_list should contain "
357357
"references to objects of BinomialTree.")
358358
obj = Heap.__new__(cls)
359-
obj.root_list = DynamicOneDimensionalArray(BinomialTree, root_list)
359+
obj.root_list = root_list
360360
return obj
361361

362362
def merge_tree(self, tree1, tree2):
@@ -387,8 +387,8 @@ def _merge_heap_last_new_tree(self, new_root_list, new_tree):
387387
"""
388388
Merges last tree node in root list with the incoming tree.
389389
"""
390-
pos = new_root_list._last_pos_filled
391-
if (new_root_list.size != 0) and new_root_list[pos].order == new_tree.order:
390+
pos = -1
391+
if len(new_root_list) > 0 and new_root_list[pos].order == new_tree.order:
392392
new_root_list[pos] = self.merge_tree(new_root_list[pos], new_tree)
393393
else:
394394
new_root_list.append(new_tree)
@@ -404,10 +404,10 @@ def merge(self, other_heap):
404404
"""
405405
if not _check_type(other_heap, BinomialHeap):
406406
raise TypeError("Other heap is not of type BinomialHeap.")
407-
new_root_list = DynamicOneDimensionalArray(BinomialTree, 0)
407+
new_root_list = []
408408
i, j = 0, 0
409-
while ((i <= self.root_list._last_pos_filled) and
410-
(j <= other_heap.root_list._last_pos_filled)):
409+
while (i < len(self.root_list)) and \
410+
(j < len(other_heap.root_list)):
411411
new_tree = None
412412
while self.root_list[i] is None:
413413
i += 1
@@ -427,11 +427,11 @@ def merge(self, other_heap):
427427
j += 1
428428
self._merge_heap_last_new_tree(new_root_list, new_tree)
429429

430-
while i <= self.root_list._last_pos_filled:
430+
while i < len(self.root_list):
431431
new_tree = self.root_list[i]
432432
self._merge_heap_last_new_tree(new_root_list, new_tree)
433433
i += 1
434-
while j <= other_heap.root_list._last_pos_filled:
434+
while j < len(other_heap.root_list):
435435
new_tree = other_heap.root_list[j]
436436
self._merge_heap_last_new_tree(new_root_list, new_tree)
437437
j += 1
@@ -486,13 +486,13 @@ def delete_minimum(self):
486486
for k, child in enumerate(min_node.children):
487487
if child is not None:
488488
child_root_list.append(BinomialTree(root=child, order=k))
489-
self.root_list.delete(min_idx)
489+
self.root_list.remove(self.root_list[min_idx])
490490
child_heap = BinomialHeap(root_list=child_root_list)
491491
self.merge(child_heap)
492492

493493
@property
494494
def is_empty(self):
495-
return self.root_list._last_pos_filled == -1
495+
return len(self.root_list) == 0
496496

497497
def decrease_key(self, node, new_key):
498498
"""

‎pydatastructs/trees/tests/test_heaps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ def test_BinomialHeap():
181181

182182
def bfs(heap):
183183
bfs_trav = []
184-
for i in range(heap.root_list._last_pos_filled + 1):
184+
for i in range(len(heap.root_list)):
185185
layer = []
186186
bfs_q = Queue()
187187
bfs_q.append(heap.root_list[i].root)

0 commit comments

Comments
 (0)
Please sign in to comment.