Files
eidp-klausuraufgaben/recursion/recursive_datastructure/README.md

95 lines
2.8 KiB
Markdown

# 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)
```
## [BinarySearchTree](./search_trees.py) (*Schwer*)
Was wäre wenn wir nun einen Binary Tree haben, dieser aber eine Sortierung hat. Wenn wir ein Element hinzufügen packen wir alle Elemente kleiner nach Links und alle anderen nach Rechts.
[Hier eine kleine Visualisierung](https://www.cs.usfca.edu/~galles/visualization/BST.html)
Probiert einfach mal rum damit ihr euch die Funktion eines BST vorstellen könnt. Wirklich komplex wird `delete`.