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

2.8 KiB

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.