# Rekursive Datenstrukturen ## [LinkedList](./lists.py) In der Vorlesung wurden uns rekursive Datenstrukturen vorgestellt. Und zwar in der einfachsten Form, einer Liste. Hierbei modellieren wir eine *Node* Datenstruktur die unseren Wert *Value* trägt und auf die nächste *Node* in der Liste verweist durch *next_node*. ```python from dataclasses import dataclass from typing import Optional @dataclass class Node[T]: value: T next_node: Optional['Node[T]'] ``` Jetzt wollen wir eine Liste um unsere Node modellieren, hierbei interessiert uns nur die erste Node *__head* und die Länge *__length*. ```python @dataclass class LinkedList[T]: def __post_init__(self): self.__head: Optional[Node[T]] = None self.__length: int = 0 ``` Jetzt geht es darum alle Standardmethoden die eine Liste braucht zu implementieren. ## [BinaryTree](./trees.py) Jetzt wollen wir eine andere rekursive Datenstruktur definieren, den binary Tree. Diese besteht immer aus zwei Abzweigungen *right* und *left*. ```python @dataclass class Node[T]: value: T left: Optional['Node[T]'] right: Optional['Node[T]'] ``` Statt jetzt eine eigene Klasse zu erstellen die `Node` intern benutzt wollen wir einfach einen Typalias erstellen und imperative mit Funktionen statt Methoden arbeiten. ```python type BinaryTree[T] = Optional[Node[T]] ``` ### `traverse` Man kann einen BinaryTree auf drei typische arten ablaufen - Inorder - Erst laufen wir Links ab - Dann schauen wir uns die Node an - Dann laufen wir Rechts ab - Preorder - Erst schauen wir uns die Node an - Dann laufen wir Links ab - Dann laufen wir Rechts ab - Postorder - Erst laufen wir Links ab - Dann laufen wir Rechts ab - Dann schauen wir uns die Node an Hierfür erstellen wir einen `Enum` um zu unterscheiden wie wir gerade ablaufen ```python class TraversalType(Enum): INORDER, POSTORDER, PREORDER = auto(), auto(), auto() ``` Und jetzt implementieren wir einen Generator der uns einen Iterator erzeugt welcher den BinaryTree in der gegebenen Order abläuft. ```python def traverse[T](tree: BinaryTree[T], order: TraversalType = TraversalType.INORDER) -> Iterator[T]: pass ``` Tipp: Mit `yield from ...` kann man einen ganzen Iterator *yield*en. ```python def my_range(start: int, end: int) -> Iterator[int]: yield from range(start, end) ```