def mst_prim(graph): # Prim's algorithm explanation https://www.youtube.com/watch?v=cplfcGZmX7I # This algorithm return list of edges, so if we have edges we may recreate MST mst = Graph(False) min_edge_heap = [] visited_vertices = set() # 1. Choose arbitary vertex from which MST algorithm start looking for edges arbitary_vertex = next(iter(graph.get_vertices())) visited_vertices.add(arbitary_vertex) mst.add_vertex(arbitary_vertex) # 2. Find all adjacent edges of arbitary vertex and add them to heap for edge in graph.get_vertex(arbitary_vertex).get_outbound_edges(): heapq.heappush(min_edge_heap, edge) input_graph_num_vertices = len(graph.get_vertices()) while len(mst.get_vertices()) < input_graph_num_vertices: # 3. Select an edge with minimum weight (greedy algorithm) while True: min_edge = heapq.heappop(min_edge_heap) min_vertex = min_edge.get_end_vertex() min_vertex_label = min_vertex.get_label() if min_vertex_label not in visited_vertices: break # 4. Mark selected vertex as visited and add selected edge to MST visited_vertices.add(min_vertex_label) mst.add_vertex(min_vertex_label) mst.add_edge(min_edge.get_start_vertex().get_label(), min_edge.get_end_vertex().get_label(), min_edge.get_weight()) # 4. Find all adjacent edges of min vertex and add them to heap for edge in min_vertex.get_outbound_edges(): heapq.heappush(min_edge_heap, edge) return mst
# 4. get all adjacent vertices which HAVE NOT been visited adjacent_vertices = [] for edge in current_vertex.get_outbound_edges(): adjacent_vertex = edge.get_end_vertex() if adjacent_vertex not in visited_vertices: adjacent_vertices.append(adjacent_vertex) # if necessary we may do some manipulation with adjacent_vertices, e.g. sort them # 5. add all adjacent vertices to the queue(BFS) queue.extend(adjacent_vertices) return result if __name__ == "__main__": graph = Graph() graph.add_vertex("Jhon") graph.add_vertex("Sophia") graph.add_vertex("Emma") graph.add_vertex("Mark") graph.add_vertex("Alice") graph.add_vertex("Jeff") graph.add_vertex("George") graph.add_edge("Jhon", "Sophia") graph.add_edge("Jhon", "Emma") graph.add_edge("Jhon", "Mark") graph.add_edge("Sophia", "Emma") graph.add_edge("Sophia", "Alice") graph.add_edge("Emma", "Sophia")
# 4. check if there is a better path from min distance vertex to each adjacent vertex min_vertex = graph.get_vertex(min_vertex_label) for edge in min_vertex.get_outbound_edges(): new_distance = min_distance + edge.get_weight() # 4. write the new distance to adjacent vertex if we have found a better path adjacent_vertex = edge.get_end_vertex() if new_distance < distances[adjacent_vertex]: distances[adjacent_vertex] = new_distance return distances if __name__ == "__main__": graph = Graph() graph.add_vertex("a") graph.add_vertex("b") graph.add_vertex("c") graph.add_vertex("d") graph.add_vertex("e") graph.add_vertex("f") graph.add_edge("a", "b", 2) graph.add_edge("a", "c", 4) graph.add_edge("b", "c", 1) graph.add_edge("c", "d", 5) graph.add_edge("c", "e", 3) graph.add_edge("d", "e", 1) graph.add_edge("e", "f", 8)
for edge in graph.get_vertex(vertex_label).get_outbound_edges(): adjacent_vertex_label = edge.get_end_vertex().get_label() indegree_dict[adjacent_vertex_label] = indegree_dict[ adjacent_vertex_label] - 1 if indegree_dict[adjacent_vertex_label] == 0: zero_indegree_vertices.put(adjacent_vertex_label) if len(topological_order) != len(graph.get_vertices()): raise ValueError("This graph is cyclic") return topological_order if __name__ == "__main__": dag = Graph() # directed acyclic graph # vertices dag.add_vertex("0") dag.add_vertex("1") dag.add_vertex("2") dag.add_vertex("3") dag.add_vertex("4") dag.add_vertex("5") dag.add_vertex("6") dag.add_vertex("7") dag.add_vertex("8") # edges dag.add_edge("0", "1") dag.add_edge("1", "2")
for edge in current_vertex.get_outbound_edges(): if edge.get_end_vertex() not in visited_vertices: adjacent_vertices.append(edge.get_end_vertex()) # push a list with path to each adjacent vertex in our queue for adjacent_vertex in adjacent_vertices: new_path = path_to_vertex.copy() new_path.append(adjacent_vertex) queue.append(new_path) # return None if there no a path between start and goal vertices return None if __name__ == "__main__": graph = Graph() graph.add_vertex("a") graph.add_vertex("b") graph.add_vertex("c") graph.add_vertex("d") graph.add_vertex("e") graph.add_vertex("f") graph.add_edge("a", "b") graph.add_edge("a", "c") graph.add_edge("a", "d") graph.add_edge("b", "c") graph.add_edge("b", "f") graph.add_edge("c", "d") graph.add_edge("d", "e")
# 4. Mark selected vertex as visited and add selected edge to MST visited_vertices.add(min_vertex_label) mst.add_vertex(min_vertex_label) mst.add_edge(min_edge.get_start_vertex().get_label(), min_edge.get_end_vertex().get_label(), min_edge.get_weight()) # 4. Find all adjacent edges of min vertex and add them to heap for edge in min_vertex.get_outbound_edges(): heapq.heappush(min_edge_heap, edge) return mst if __name__ == "__main__": graph = Graph(False) # undirected weighted graph graph.add_vertex("a") graph.add_vertex("b") graph.add_vertex("c") graph.add_vertex("d") graph.add_vertex("e") graph.add_vertex("f") graph.add_vertex("g") graph.add_edge("a", "b", 2) graph.add_edge("a", "c", 3) graph.add_edge("a", "d", 3) graph.add_edge("b", "c", 4) graph.add_edge("b", "e", 3) graph.add_edge("c", "d", 5)
def mst_kruskal(graph): # Kruskal's algorithm explanation https://www.youtube.com/watch?v=71UQH7Pr9kU mst = Graph(False) min_edge_heap = [ ] # use as priority queue to select and edge with minimum weight # 1. Sort the edges in ascending order of weights for edge in graph.get_edges(): heapq.heappush(min_edge_heap, edge) input_graph_num_vertices = len(graph.get_vertices()) # 2. Keep adding edges until MST will reach all vertices while (len(min_edge_heap) > 0) and (len(mst.get_vertices()) < input_graph_num_vertices): # 3. Select an edge with minimum weight (greedy algorithm) min_edge = heapq.heappop(min_edge_heap) start_vertex = min_edge.get_start_vertex() end_vertex = min_edge.get_end_vertex() # 4. Add edge in MST and check if it form a cycle then remove edge, otherwise leave it in MST mst.add_vertex(start_vertex.get_label()) mst.add_vertex(end_vertex.get_label()) start_label = start_vertex.get_label() end_label = end_vertex.get_label() weight = min_edge.get_weight() mst.add_edge(start_label, end_label, weight) if has_cycle(mst): mst.remove_edge(start_label, end_label, weight) return mst