You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mst.py 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. import math
  2. import re
  3. from SoSe24.lec06_graph.disjoint import DisjointValue
  4. from graph import Graph, AdjacencyListGraph, AdjacencyMatrixGraph, Vertex
  5. import heapq
  6. def mst_prim(self, start_name: str = None):
  7. """ Compute the minimum spanning tree of the graph using Prim's algorithm. """
  8. distance_map = {} # maps vertices to their current distance from the spanning tree
  9. parent_map = {} # maps vertices to their predecessor in the spanning tree
  10. Vertex.__lt__ = lambda self, other: distance_map[self] < distance_map[other]
  11. queue = []
  12. if start_name is None:
  13. start_name = self.all_vertices()[0].value;
  14. # Initialize the maps
  15. for vertex in self.all_vertices():
  16. distance_map[vertex] = 0 if vertex.value == start_name else math.inf
  17. parent_map[vertex] = None
  18. queue.append(vertex)
  19. heapq.heapify(queue) # Convert the list into a heap
  20. # Process the queue
  21. cost = 0 # The cost of the minimum spanning tree
  22. while len(queue) > 0:
  23. vertex = heapq.heappop(queue)
  24. cost += distance_map[vertex] # Add the cost of the edge to the minimum spanning tree
  25. for (dest, w) in self.get_adjacent_vertices_with_weight(vertex.value):
  26. if dest in queue and distance_map[dest] > w:
  27. # Update the distance and parent maps
  28. queue.remove(dest)
  29. distance_map[dest] = w
  30. parent_map[dest] = vertex
  31. queue.append(dest) # Add the vertex back to the queue
  32. heapq.heapify(queue) # Re-heapify the queue
  33. # Return the distance and predecessor maps
  34. return parent_map, cost
  35. def mst_kruskal(self, start_name: str = None):
  36. """ Compute the minimum spanning tree of the graph using Kruskal's algorithm. """
  37. cost = 0
  38. result = []
  39. edges = self.all_edges()
  40. # Create a disjoint set for each vertex
  41. vertex_map = {v.value: DisjointValue(v) for v in self.all_vertices()}
  42. # Sort the edges by weight
  43. edges.sort(key=lambda edge: edge[2])
  44. # Process the edges
  45. for edge in edges:
  46. start_name, end_name, weight = edge
  47. # Check if the edge creates a cycle
  48. if not vertex_map[start_name].same_set(vertex_map[end_name]):
  49. result.append(edge)
  50. vertex_map[start_name].union(vertex_map[end_name])
  51. cost += weight
  52. return result, cost
  53. AdjacencyListGraph.mst_prim = mst_prim
  54. AdjacencyMatrixGraph.mst_prim = mst_prim
  55. AdjacencyListGraph.mst_kruskal = mst_kruskal
  56. AdjacencyMatrixGraph.mst_kruskal = mst_kruskal
  57. def read_elektro_into_graph(graph: Graph, filename: str):
  58. pattern = re.compile(r'"([^"]+)";"([^"]+)";(\d+)')
  59. with (open(filename, "r") as file):
  60. for line in file:
  61. m = pattern.match(line)
  62. if m:
  63. start_name = m.group(1)
  64. end_name = m.group(2)
  65. cost = int(m.group(3))
  66. graph.insert_vertex(start_name)
  67. graph.insert_vertex(end_name)
  68. graph.connect(start_name, end_name, cost)
  69. graph.connect(end_name, start_name, cost)
  70. if __name__ == "__main__":
  71. graph = AdjacencyMatrixGraph()
  72. read_elektro_into_graph(graph, "../../elektro.txt")
  73. parents, cost = graph.mst_prim()
  74. print(f"Kosten nach Prim: {cost}")
  75. for node, parent in parents.items():
  76. if parent is not None:
  77. print(f"{node} - {parent}")
  78. edges, cost = graph.mst_kruskal()
  79. print(f"Kosten nach Kruskal: {cost}")
  80. for start_name, end_name, _ in edges:
  81. print(f"{start_name} - {end_name}")