Lecture 7
This commit is contained in:
parent
00466b6ad7
commit
242b7fdc34
52
SoSe24/lec03_sort_alg/algdat_heap.py
Normal file
52
SoSe24/lec03_sort_alg/algdat_heap.py
Normal file
@ -0,0 +1,52 @@
|
||||
from SoSe24.algodat.foundation import AlgoDatArray
|
||||
|
||||
|
||||
class AlgoDatHeap():
|
||||
|
||||
def __init__(self, values: AlgoDatArray):
|
||||
self.heap = values
|
||||
self.size = len(values)
|
||||
|
||||
def left_child(self, i):
|
||||
return 2*i + 1
|
||||
|
||||
def right_child(self, i):
|
||||
return 2*i + 2
|
||||
|
||||
def parent(self, i):
|
||||
return (i-1)//2
|
||||
|
||||
def max_heapify(self, i):
|
||||
l = self.left_child(i)
|
||||
r = self.right_child(i)
|
||||
largest = i
|
||||
if l <= self.size and self.heap[l-1] > self.heap[i-1]:
|
||||
largest = l
|
||||
if r <= self.size and self.heap[r-1] > self.heap[largest-1]:
|
||||
largest = r
|
||||
if largest != i:
|
||||
self.heap[i-1], self.heap[largest-1] = self.heap[largest-1], self.heap[i-1]
|
||||
self.max_heapify(largest)
|
||||
|
||||
def min_heapify(self, i):
|
||||
l = self.left_child(i)
|
||||
r = self.right_child(i)
|
||||
smallest = i
|
||||
if l <= self.size and self.heap[l-1] < self.heap[i-1]:
|
||||
smallest = l
|
||||
if r <= self.size and self.heap[r-1] < self.heap[smallest-1]:
|
||||
smallest = r
|
||||
if smallest != i:
|
||||
self.heap[i-1], self.heap[smallest-1] = self.heap[smallest-1], self.heap[i-1]
|
||||
self.min_heapify(smallest)
|
||||
|
||||
def build_max_heap(self):
|
||||
for i in range(self.size//2, 0, -1):
|
||||
self.max_heapify(i)
|
||||
|
||||
def build_min_heap(self):
|
||||
for i in range(self.size//2, 0, -1):
|
||||
self.min_heapify(i)
|
||||
|
||||
def as_list(self):
|
||||
return [self.heap[i].value for i in range(self.size)]
|
18
SoSe24/lec06_graph/disjoint.py
Normal file
18
SoSe24/lec06_graph/disjoint.py
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
class DisjointValue():
|
||||
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.parent = None
|
||||
|
||||
def canonical(self):
|
||||
if self.parent:
|
||||
return self.parent.canonical()
|
||||
return self
|
||||
|
||||
def same_set(self, other):
|
||||
return self.canonical() == other.canonical()
|
||||
|
||||
def union(self, other):
|
||||
self.canonical().parent = other.canonical()
|
@ -39,6 +39,8 @@ class Graph:
|
||||
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
|
||||
raise NotImplementedError("Please implement this method in subclass")
|
||||
|
||||
def all_edges(self) -> List[tuple[str, str, float]]:
|
||||
raise NotImplementedError("Please implement this method in subclass")
|
||||
|
||||
def bfs(self, start_name: str):
|
||||
"""
|
||||
@ -124,6 +126,12 @@ class AdjacencyListGraph(Graph):
|
||||
|
||||
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
|
||||
return self.adjacency_map[name]
|
||||
def all_edges(self) -> List[tuple[str, str, float]]:
|
||||
result = []
|
||||
for name in self.adjacency_map:
|
||||
for (dest, weight) in self.adjacency_map[name]:
|
||||
result.append((name, dest.value, weight))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@ -173,7 +181,13 @@ class AdjacencyMatrixGraph(Graph):
|
||||
result.append((self.get_vertex(name), self.adjacency_matrix[index][i]))
|
||||
return result
|
||||
|
||||
|
||||
def all_edges(self) -> List[tuple[str, str, float]]:
|
||||
result = []
|
||||
for i in range(len(self.vertex_list)):
|
||||
for j in range(len(self.vertex_list)):
|
||||
if self.adjacency_matrix[i][j] is not None:
|
||||
result.append((self.vertex_list[i].value, self.vertex_list[j].value, self.adjacency_matrix[i][j]))
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
@ -1,13 +1,16 @@
|
||||
import math
|
||||
import re
|
||||
from graph import Graph, AdjacencyListGraph, AdjacencyMatrixGraph, NodeColor, Vertex
|
||||
|
||||
from SoSe24.lec06_graph.disjoint import DisjointValue
|
||||
from graph import Graph, AdjacencyListGraph, AdjacencyMatrixGraph, Vertex
|
||||
import heapq
|
||||
|
||||
|
||||
def mst_prim(self, start_name: str = None):
|
||||
""" Compute the minimum spanning tree of the graph using Prim's algorithm. """
|
||||
|
||||
distance_map = {}
|
||||
parent_map = {}
|
||||
distance_map = {} # maps vertices to their current distance from the spanning tree
|
||||
parent_map = {} # maps vertices to their predecessor in the spanning tree
|
||||
|
||||
Vertex.__lt__ = lambda self, other: distance_map[self] < distance_map[other]
|
||||
|
||||
@ -20,26 +23,60 @@ def mst_prim(self, start_name: str = None):
|
||||
for vertex in self.all_vertices():
|
||||
distance_map[vertex] = 0 if vertex.value == start_name else math.inf
|
||||
parent_map[vertex] = None
|
||||
heapq.heappush(queue, vertex)
|
||||
queue.append(vertex)
|
||||
|
||||
heapq.heapify(queue) # Convert the list into a heap
|
||||
|
||||
# Process the queue
|
||||
cost = 0
|
||||
cost = 0 # The cost of the minimum spanning tree
|
||||
while len(queue) > 0:
|
||||
vertex = heapq.heappop(queue)
|
||||
cost += distance_map[vertex]
|
||||
cost += distance_map[vertex] # Add the cost of the edge to the minimum spanning tree
|
||||
for (dest, w) in self.get_adjacent_vertices_with_weight(vertex.value):
|
||||
if dest in queue and distance_map[dest] > w:
|
||||
# Update the distance and parent maps
|
||||
queue.remove(dest)
|
||||
distance_map[dest] = w
|
||||
parent_map[dest] = vertex
|
||||
heapq.heappush(queue, dest)
|
||||
queue.append(dest) # Add the vertex back to the queue
|
||||
heapq.heapify(queue) # Re-heapify the queue
|
||||
|
||||
# Return the distance and predecessor maps
|
||||
return parent_map, cost
|
||||
|
||||
|
||||
def mst_kruskal(self, start_name: str = None):
|
||||
""" Compute the minimum spanning tree of the graph using Kruskal's algorithm. """
|
||||
|
||||
cost = 0
|
||||
result = []
|
||||
edges = self.all_edges()
|
||||
|
||||
# Create a disjoint set for each vertex
|
||||
vertex_map = {v.value: DisjointValue(v) for v in self.all_vertices()}
|
||||
|
||||
# Sort the edges by weight
|
||||
edges.sort(key=lambda edge: edge[2])
|
||||
|
||||
# Process the edges
|
||||
for edge in edges:
|
||||
start_name, end_name, weight = edge
|
||||
# Check if the edge creates a cycle
|
||||
if not vertex_map[start_name].same_set(vertex_map[end_name]):
|
||||
result.append(edge)
|
||||
vertex_map[start_name].union(vertex_map[end_name])
|
||||
cost += weight
|
||||
|
||||
return result, cost
|
||||
|
||||
|
||||
|
||||
AdjacencyListGraph.mst_prim = mst_prim
|
||||
AdjacencyMatrixGraph.mst_prim = mst_prim
|
||||
|
||||
AdjacencyListGraph.mst_kruskal = mst_kruskal
|
||||
AdjacencyMatrixGraph.mst_kruskal = mst_kruskal
|
||||
|
||||
|
||||
def read_elektro_into_graph(graph: Graph, filename: str):
|
||||
pattern = re.compile(r'"([^"]+)";"([^"]+)";(\d+)')
|
||||
@ -59,8 +96,16 @@ if __name__ == "__main__":
|
||||
|
||||
graph = AdjacencyMatrixGraph()
|
||||
read_elektro_into_graph(graph, "../../elektro.txt")
|
||||
|
||||
parents, cost = graph.mst_prim()
|
||||
print(f"Kosten {cost}")
|
||||
print(f"Kosten nach Prim: {cost}")
|
||||
for node, parent in parents.items():
|
||||
if parent is not None:
|
||||
print(f"{node} - {parent}")
|
||||
print(f"{node} - {parent}")
|
||||
|
||||
edges, cost = graph.mst_kruskal()
|
||||
print(f"Kosten nach Kruskal: {cost}")
|
||||
for start_name, end_name, _ in edges:
|
||||
print(f"{start_name} - {end_name}")
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user