Browse Source

Lecture 7

master
Oliver Hofmann 6 months ago
parent
commit
242b7fdc34

+ 52
- 0
SoSe24/lec03_sort_alg/algdat_heap.py View 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
- 0
SoSe24/lec06_graph/disjoint.py View 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()

+ 15
- 1
SoSe24/lec06_graph/graph.py View File

@@ -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




+ 54
- 9
SoSe24/lec06_graph/mst.py View File

@@ -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…
Cancel
Save