Skip to content

Added sequential Prim's algorithm #210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion pydatastructs/graphs/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from collections import deque as Queue
from concurrent.futures import ThreadPoolExecutor
from pydatastructs.utils import GraphEdge
from pydatastructs.miscellaneous_data_structures import DisjointSetForest
from pydatastructs.miscellaneous_data_structures import (
DisjointSetForest, PriorityQueue)
from pydatastructs.graphs.graph import Graph
from pydatastructs.linear_data_structures.algorithms import merge_sort_parallel

Expand Down Expand Up @@ -215,12 +216,36 @@ def _minimum_spanning_tree_kruskal_adjacency_list(graph):
u, v = edge.source.name, edge.target.name
if dsf.find_root(u) is not dsf.find_root(v):
mst.add_edge(u, v, edge.value)
mst.add_edge(v, u, edge.value)
dsf.union(u, v)
return mst

_minimum_spanning_tree_kruskal_adjacency_matrix = \
_minimum_spanning_tree_kruskal_adjacency_list

def _minimum_spanning_tree_prim_adjacency_list(graph):
q = PriorityQueue(implementation='binomial_heap')
e = dict()
mst = Graph(implementation='adjacency_list')
q.push(next(iter(graph.vertices)), 0)
while not q.is_empty:
v = q.pop()
if not hasattr(mst, v):
mst.add_vertex(graph.__getattribute__(v))
if e.get(v, None) is not None:
edge = e[v]
mst.add_vertex(edge.target)
mst.add_edge(edge.source.name, edge.target.name, edge.value)
mst.add_edge(edge.target.name, edge.source.name, edge.value)
for w_node in graph.neighbors(v):
w = w_node.name
vw = graph.edge_weights[v + '_' + w]
q.push(w, vw.value)
if e.get(w, None) is None or \
e[w].value > vw.value:
e[w] = vw
return mst

def minimum_spanning_tree(graph, algorithm):
"""
Computes a minimum spanning tree for the given
Expand All @@ -239,6 +264,7 @@ def minimum_spanning_tree(graph, algorithm):
supported,
'kruskal' -> Kruskal's algorithm as given in
[1].
'prim' -> Prim's algorithm as given in [2].

Returns
=======
Expand All @@ -265,6 +291,7 @@ def minimum_spanning_tree(graph, algorithm):
==========

.. [1] https://en.wikipedia.org/wiki/Kruskal%27s_algorithm
.. [2] https://en.wikipedia.org/wiki/Prim%27s_algorithm

Note
====
Expand Down Expand Up @@ -293,6 +320,7 @@ def _minimum_spanning_tree_parallel_kruskal_adjacency_list(graph, num_threads):
u, v = edge.source.name, edge.target.name
if dsf.find_root(u) is not dsf.find_root(v):
mst.add_edge(u, v, edge.value)
mst.add_edge(v, u, edge.value)
dsf.union(u, v)
return mst

Expand Down
5 changes: 3 additions & 2 deletions pydatastructs/graphs/tests/test_algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,13 @@ def _test_minimum_spanning_tree(ds, algorithm):
mst = minimum_spanning_tree(graph, algorithm=algorithm)
expected_mst = [('0_3', 7), ('2_3', 9), ('3_4', 23), ('3_1', 32),
('3_0', 7), ('3_2', 9), ('4_3', 23), ('1_3', 32)]
assert len(expected_mst) == 2*len(mst.edge_weights.items())
assert len(expected_mst) == len(mst.edge_weights.items())
for k, v in mst.edge_weights.items():
assert (k, v.value) in expected_mst

_test_minimum_spanning_tree("List", "kruskal")
_test_minimum_spanning_tree("Matrix", "kruskal")
_test_minimum_spanning_tree("List", "prim")

def test_minimum_spanning_tree_parallel():

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

Expand Down
20 changes: 10 additions & 10 deletions pydatastructs/trees/heaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ def __new__(cls, root_list=[]):
raise TypeError("The root_list should contain "
"references to objects of BinomialTree.")
obj = Heap.__new__(cls)
obj.root_list = DynamicOneDimensionalArray(BinomialTree, root_list)
obj.root_list = root_list
return obj

def merge_tree(self, tree1, tree2):
Expand Down Expand Up @@ -387,8 +387,8 @@ def _merge_heap_last_new_tree(self, new_root_list, new_tree):
"""
Merges last tree node in root list with the incoming tree.
"""
pos = new_root_list._last_pos_filled
if (new_root_list.size != 0) and new_root_list[pos].order == new_tree.order:
pos = -1
if len(new_root_list) > 0 and new_root_list[pos].order == new_tree.order:
new_root_list[pos] = self.merge_tree(new_root_list[pos], new_tree)
else:
new_root_list.append(new_tree)
Expand All @@ -404,10 +404,10 @@ def merge(self, other_heap):
"""
if not _check_type(other_heap, BinomialHeap):
raise TypeError("Other heap is not of type BinomialHeap.")
new_root_list = DynamicOneDimensionalArray(BinomialTree, 0)
new_root_list = []
i, j = 0, 0
while ((i <= self.root_list._last_pos_filled) and
(j <= other_heap.root_list._last_pos_filled)):
while (i < len(self.root_list)) and \
(j < len(other_heap.root_list)):
new_tree = None
while self.root_list[i] is None:
i += 1
Expand All @@ -427,11 +427,11 @@ def merge(self, other_heap):
j += 1
self._merge_heap_last_new_tree(new_root_list, new_tree)

while i <= self.root_list._last_pos_filled:
while i < len(self.root_list):
new_tree = self.root_list[i]
self._merge_heap_last_new_tree(new_root_list, new_tree)
i += 1
while j <= other_heap.root_list._last_pos_filled:
while j < len(other_heap.root_list):
new_tree = other_heap.root_list[j]
self._merge_heap_last_new_tree(new_root_list, new_tree)
j += 1
Expand Down Expand Up @@ -486,13 +486,13 @@ def delete_minimum(self):
for k, child in enumerate(min_node.children):
if child is not None:
child_root_list.append(BinomialTree(root=child, order=k))
self.root_list.delete(min_idx)
self.root_list.remove(self.root_list[min_idx])
child_heap = BinomialHeap(root_list=child_root_list)
self.merge(child_heap)

@property
def is_empty(self):
return self.root_list._last_pos_filled == -1
return len(self.root_list) == 0

def decrease_key(self, node, new_key):
"""
Expand Down
2 changes: 1 addition & 1 deletion pydatastructs/trees/tests/test_heaps.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def test_BinomialHeap():

def bfs(heap):
bfs_trav = []
for i in range(heap.root_list._last_pos_filled + 1):
for i in range(len(heap.root_list)):
layer = []
bfs_q = Queue()
bfs_q.append(heap.root_list[i].root)
Expand Down