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]]:
|
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
|
||||||
raise NotImplementedError("Please implement this method in subclass")
|
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):
|
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]]:
|
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
|
||||||
return self.adjacency_map[name]
|
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]))
|
result.append((self.get_vertex(name), self.adjacency_matrix[index][i]))
|
||||||
return result
|
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 math
|
||||||
import re
|
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
|
import heapq
|
||||||
|
|
||||||
|
|
||||||
def mst_prim(self, start_name: str = None):
|
def mst_prim(self, start_name: str = None):
|
||||||
|
""" Compute the minimum spanning tree of the graph using Prim's algorithm. """
|
||||||
|
|
||||||
distance_map = {}
|
distance_map = {} # maps vertices to their current distance from the spanning tree
|
||||||
parent_map = {}
|
parent_map = {} # maps vertices to their predecessor in the spanning tree
|
||||||
|
|
||||||
Vertex.__lt__ = lambda self, other: distance_map[self] < distance_map[other]
|
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():
|
for vertex in self.all_vertices():
|
||||||
distance_map[vertex] = 0 if vertex.value == start_name else math.inf
|
distance_map[vertex] = 0 if vertex.value == start_name else math.inf
|
||||||
parent_map[vertex] = None
|
parent_map[vertex] = None
|
||||||
heapq.heappush(queue, vertex)
|
queue.append(vertex)
|
||||||
|
|
||||||
|
heapq.heapify(queue) # Convert the list into a heap
|
||||||
|
|
||||||
# Process the queue
|
# Process the queue
|
||||||
cost = 0
|
cost = 0 # The cost of the minimum spanning tree
|
||||||
while len(queue) > 0:
|
while len(queue) > 0:
|
||||||
vertex = heapq.heappop(queue)
|
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):
|
for (dest, w) in self.get_adjacent_vertices_with_weight(vertex.value):
|
||||||
if dest in queue and distance_map[dest] > w:
|
if dest in queue and distance_map[dest] > w:
|
||||||
|
# Update the distance and parent maps
|
||||||
queue.remove(dest)
|
queue.remove(dest)
|
||||||
distance_map[dest] = w
|
distance_map[dest] = w
|
||||||
parent_map[dest] = vertex
|
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 the distance and predecessor maps
|
||||||
return parent_map, cost
|
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
|
AdjacencyListGraph.mst_prim = mst_prim
|
||||||
AdjacencyMatrixGraph.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):
|
def read_elektro_into_graph(graph: Graph, filename: str):
|
||||||
pattern = re.compile(r'"([^"]+)";"([^"]+)";(\d+)')
|
pattern = re.compile(r'"([^"]+)";"([^"]+)";(\d+)')
|
||||||
@ -59,8 +96,16 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
graph = AdjacencyMatrixGraph()
|
graph = AdjacencyMatrixGraph()
|
||||||
read_elektro_into_graph(graph, "../../elektro.txt")
|
read_elektro_into_graph(graph, "../../elektro.txt")
|
||||||
|
|
||||||
parents, cost = graph.mst_prim()
|
parents, cost = graph.mst_prim()
|
||||||
print(f"Kosten {cost}")
|
print(f"Kosten nach Prim: {cost}")
|
||||||
for node, parent in parents.items():
|
for node, parent in parents.items():
|
||||||
if parent is not None:
|
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