diff --git a/generics/graphen/README.md b/generics/graphen/README.md new file mode 100644 index 0000000..147535e --- /dev/null +++ b/generics/graphen/README.md @@ -0,0 +1,34 @@ +# Graphen + +## Graph-Klasse + +Wir wollen hier einen Graphen modellieren, Graphen kennt ihr bereits als Bäume. Diese sind spezielle Graphen welche eine Wurzel haben, also den ersten Knoten. Und dann immer maximal zwei weitere Knoten (**left** und **right**). Die letzten Knoten nennt man auch Blätter. Allgemeine Graphen hingegen kann jeder Knoten auf beliebig viele weitere Knoten verweisen. Diese Verweise nennt man Kanten. + +Unsere **Graph** Klasse modellieren wir etwas anders mit einem `dict` welcher immer einen Knoten auf eine Liste von weiteren Knoten mappt. + +```python +from dataclasses import dataclass, field + + +@dataclass +class Graph[T]: + vertecies: dict[T, list[T]] = field(default_factory=dict) +``` + +Als Beispiel: + +![image not found](image.png) + +würde dann im Code so aussehen: + +```python + +my_graph: Graph[str] = Graph( + vertecies={ + 'A': ['B', 'D'], + 'B': ['A', 'C'], + 'C': ['B', 'D'], + 'D': ['C', 'A'], + }) + +``` \ No newline at end of file diff --git a/generics/graphen/graphs.py b/generics/graphen/graphs.py new file mode 100644 index 0000000..e1d12ed --- /dev/null +++ b/generics/graphen/graphs.py @@ -0,0 +1,60 @@ +type Graph[T] = dict[T, list[T]] + + +def is_bidirected[T](graph: Graph[T]) -> bool: + for a, vertecies in graph.items(): + for b in vertecies: + if a not in graph[b]: + return False + return True + + +def depth_first_search[T](graph: Graph[T], node: T, + _visited: set[T] = None) -> set[T]: + if _visited is None: + _visited = set() + if node in _visited: + return set() + _visited.add(node) + for neighbours in graph[node]: + depth_first_search(graph, neighbours, _visited) + return _visited + + +def all_edges[T](graph: Graph[T]) -> set[tuple[T, T]]: + all_vertecies = set() + for a, vertecies in graph.items(): + for b in vertecies: + all_vertecies.add((a, b)) + return all_vertecies + + +def alt_all_edges[T](graph: Graph[T]) -> set[tuple[T, T]]: + return {(a, b) + for a, vertecies in graph.items() + for b in vertecies} + + +if __name__ == '__main__': + my_graph: Graph[str] = { + 'A': ['B', 'D'], + 'B': ['A', 'C'], + 'C': ['B', 'D'], + 'D': ['C', 'A'], + } + assert all_edges(my_graph) == {('A', 'B'), ('A', 'D'), ('B', 'A'), + ('B', 'C'), ('C', 'B'), ('C', 'D'), + ('D', 'C'), ('D', 'A')} + assert all_edges(my_graph) == alt_all_edges(my_graph) + assert is_bidirected(my_graph) + assert not is_bidirected({'A': ['B', 'C'], 'B': [ + 'C'], 'C': ['A', 'B']}) + my_graph = { + 0: [1, 2, 3], + 1: [0], + 2: [3, 4, 0], + 3: [0, 2], + 4: [2], + 5: [], + } + print(depth_first_search(my_graph, 5)) \ No newline at end of file diff --git a/generics/graphen/image.png b/generics/graphen/image.png new file mode 100644 index 0000000..0c4f8bb Binary files /dev/null and b/generics/graphen/image.png differ