Rekursive Datenstrukturen
LinkedList
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.
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.
@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
Jetzt wollen wir eine andere rekursive Datenstruktur definieren, den binary Tree. Diese besteht immer aus zwei Abzweigungen right und left.
@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.
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
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.
def traverse[T](tree: BinaryTree[T], order: TraversalType = TraversalType.INORDER) -> Iterator[T]:
pass
Tipp:
Mit yield from ...
kann man einen ganzen Iterator yielden.
def my_range(start: int, end: int) -> Iterator[int]:
yield from range(start, end)
BinarySearchTree (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
Probiert einfach mal rum damit ihr euch die Funktion eines BST vorstellen könnt. Wirklich komplex wird delete
.