3131"""
3232Minimization and maximization algorithms.
3333
34- @sort: heuristic_search, minimal_spanning_tree, shortest_path ,
35- shortest_path_bellman_ford
34+ @sort: heuristic_search, minimal_spanning_tree_prim ,
35+ minimal_spanning_tree_kruskal, shortest_path, shortest_path_bellman_ford
3636"""
3737
3838from pygraph .algorithms .utils import heappush , heappop
3939from pygraph .classes .exceptions import NodeUnreachable
4040from pygraph .classes .exceptions import NegativeWeightCycleError
4141from pygraph .classes .digraph import digraph
42+ from pygraph .classes .unionfind import UnionFind
43+ import heapq
4244import bisect
4345
4446# Minimal spanning tree
4547
46- def minimal_spanning_tree (graph , root = None ):
48+
49+ def minimal_spanning_tree_prim (graph , root = None , parallel = None ):
4750 """
48- Minimal spanning tree.
51+ Minimal spanning tree constructed with prim's algorithm .
4952
5053 @attention: Minimal spanning tree is meaningful only for weighted graphs.
5154
5255 @type graph: graph
5356 @param graph: Graph.
54-
57+
5558 @type root: node
5659 @param root: Optional root node (will explore only root's connected component)
5760
5861 @rtype: dictionary
5962 @return: Generated spanning tree.
6063 """
6164 visited = [] # List for marking visited and non-visited nodes
62- spanning_tree = {} # MInimal Spanning tree
65+ spanning_tree = {} # Minimal Spanning tree
6366
6467 # Initialization
6568 if (root is not None ):
@@ -68,11 +71,11 @@ def minimal_spanning_tree(graph, root=None):
6871 spanning_tree [root ] = None
6972 else :
7073 nroot = 1
71-
74+
7275 # Algorithm loop
7376 while (nroot is not None ):
7477 ledge = _lightest_edge (graph , visited )
75- if (ledge == None ):
78+ if (ledge is None ):
7679 if (root is not None ):
7780 break
7881 nroot = _first_unvisited (graph , visited )
@@ -81,11 +84,59 @@ def minimal_spanning_tree(graph, root=None):
8184 visited .append (nroot )
8285 else :
8386 spanning_tree [ledge [1 ]] = ledge [0 ]
87+ spanning_tree [ledge [0 ]] = ledge [1 ]
8488 visited .append (ledge [1 ])
8589
8690 return spanning_tree
8791
8892
93+ def minimal_spanning_tree_kruskal (graph , root = None , parallel = None ):
94+ """
95+ Minimal spanning tree constructed with kruskal's algorithm.
96+
97+ @attention: Minimal spanning tree is meaningful only for weighted graphs.
98+
99+ @type graph: graph
100+ @param graph: Graph.
101+
102+ @type root: node
103+ @param root: Optional root node (will explore only root's connected component)
104+
105+ @rtype: dictionary
106+ @return: Generated spanning tree.
107+ """
108+
109+ EDGE_WEIGHT = 0
110+ EDGE_OBJ = 1
111+
112+ if root is not None :
113+ # Will be implemented later
114+ pass
115+ else :
116+ root = 0
117+
118+ spanning_tree = {}
119+ edges = graph .edges ()
120+ num_edges = len (edges )
121+ edges_heap = []
122+
123+ for edge in [(graph .edge_weight (edge ), edge ) for edge in edges ]:
124+ heapq .heappush (edges_heap , edge )
125+ heapq .heapify (edges_heap )
126+
127+ spanning_tree [root ] = None
128+ cycle_checker = UnionFind (num_edges )
129+ for min_edge in range (num_edges ):
130+ min_elem = heapq .heappop (edges_heap )
131+ min_edge = min_elem [EDGE_OBJ ]
132+ if not cycle_checker .find (min_edge [0 ], min_edge [1 ]):
133+ cycle_checker .union (min_edge [0 ], min_edge [1 ])
134+ spanning_tree [min_edge [1 ]] = min_edge [0 ]
135+ spanning_tree [min_edge [0 ]] = min_edge [1 ]
136+
137+ return spanning_tree
138+
139+
89140def _first_unvisited (graph , visited ):
90141 """
91142 Return first unvisited node.
@@ -138,7 +189,7 @@ def shortest_path(graph, source):
138189 algorithm.
139190
140191 @attention: All weights must be nonnegative.
141-
192+
142193 @see: shortest_path_bellman_ford
143194
144195 @type graph: graph, digraph
0 commit comments