diff --git a/pydatastructs/graphs/algorithms.py b/pydatastructs/graphs/algorithms.py index 79cfeaef3..e6e298c4e 100644 --- a/pydatastructs/graphs/algorithms.py +++ b/pydatastructs/graphs/algorithms.py @@ -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 @@ -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 @@ -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 ======= @@ -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 ==== @@ -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 diff --git a/pydatastructs/graphs/tests/test_algorithms.py b/pydatastructs/graphs/tests/test_algorithms.py index 5bce06b19..c4a373e79 100644 --- a/pydatastructs/graphs/tests/test_algorithms.py +++ b/pydatastructs/graphs/tests/test_algorithms.py @@ -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(): @@ -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 diff --git a/pydatastructs/trees/heaps.py b/pydatastructs/trees/heaps.py index df9df4411..ee69c7b99 100644 --- a/pydatastructs/trees/heaps.py +++ b/pydatastructs/trees/heaps.py @@ -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): @@ -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) @@ -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 @@ -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 @@ -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): """ diff --git a/pydatastructs/trees/tests/test_heaps.py b/pydatastructs/trees/tests/test_heaps.py index 34495073f..ed9fedff4 100644 --- a/pydatastructs/trees/tests/test_heaps.py +++ b/pydatastructs/trees/tests/test_heaps.py @@ -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)