Wir haben in vorherigen Beispielen und Übungsaufgaben gesehen, dass Binärbäume leicht degenerieren können und ihre Höhe
dann nicht mehr $h \simeq\log_2(n)$ entspricht. Da alle Baumoperationen in $\mathcal{O}(h)$ liegen, ist das ein fatales
Problem. Der Lösungsansatz liegt auf der Hand: Wir müssen die Bäume balanciert halten.
Dazu gibt es mehrere Ansätze, der älteste ist der AVL-Baum (1962). In dieser Verfeinerung eine Binärbaums wird sofort ein relativ ressourcensparender
Balanciermechanismus, das Rotieren (todo: PIC) gestartet, sobald die Höhe des Linken Unterbaums sich von der Höhe des rechten Unterbaums um
$\leq2$ unterscheidet. Dieses Modell ist sehr strikt und einfach zu verstehen, aber durch die Striktheit wird der
Balanciermechanismus öfter aktiviert, als eigentlich nötig wäre.
Eine andere Möglichkeit sind $(2-4)$-Bäume. Diese sind keine Binärbäume, sondern jedes nicht-Blatt hat zwei, drei oder
vier Kinder.
Durch das Speichern der Nutzdaten in Blättern ist damit die Höhe $\log_4 n ≤ h ≤ log_2 n$ garantiert.
Wird beim Einfügen die Obergrenze von vier Kindern verletzt, wird der entsprechende Knoten in zwei Knoten
aufgeteilt. Damit kann diese Verletzung nach oben weitergegeben werden, aber nach spätestens $h$ Schritten ist diese
Bedingung wieder erfüllt.
Analog kann beim Löschen eines Blattes die Untergrenze verletzt werden. Zur Korrektur werden nun Nachbarknoten
zusammengelegt, potentiell wieder rekursiv bis zur Wurzel.
Da nicht-Binärbäume aufwendig in der Formalisierung und Implementierung sind, schauen wir uns ein sehr verwandtes Konzept an:
Den Red-Black-Tree.
\begin{definition}[RBT]
Red-Black-Trees (RBT) über einen Datentyp $D$ sind Binäre Suchbäume, bei denen jeder Knoten zusätzlich eine Farbe aus
$\{R,B\}$ abspeichert.
Folgende zwei Invarianzen müssen zudem immer gewahrt werden:
\begin{itemize}
\item[lokal] Ein Roter Knoten darf keinen roten Kindknoten haben.
\item[global] Jeder Pfad von der Wurzel zu einem Blatt durchschreitet die gleiche Anzahl schwarzer Knoten.
\end{itemize}
\end{definition}
Per Konvention nehmen wir an, dass der Wurzelknoten immer Schwarz ist.
Wenn der kürzeste vorstellbare Pfad von der Wurzel zu einem Blatt in einem RBT-Tree durch $l$ ausschließlich durch schwarze Knoten geht, ist der längste
Pfad dann durch $2l$ Knoten, immer einen Schwarzen und einen roten. Dadurch ist gewährleistet, dass das höchste Blatt
maximal halb so hoch hängt wie eins auf der untersten Ebene.
Dadurch folgt:
\begin{lemma}
In einem nichtlehren Red-Black-Tree der Größe $n$ liegt die Höhe $h$ in $Θ(\log n)$.
\label{lemma:RBT_height}
\end{lemma}
Die Details des Beweises sind eine Übungsaufgabe.
\subsection{Einfügen in Red-Black-Trees}
Da RBT insbesondere Binäre Suchbäume sind, sind die Operationen zum Suchen von Elementen, dem Finden des Maximums,
Minimums, Nachfolgers etc identisch.
Auch die grundsätzliche Idee des Einfügens bleibt gleich: Wie bei BST gehen wir von der Wurzel abwärts und suchen dabei
den passenden Platz für das neue Element. Eingefügte Elemente sind also erst einmal Blätter.
Würde man das neue Blatt schwarz färben, wäre sofort die globale Invarianz verletzt. Daher färben wir das neue Blatt
rot. Allerdings kann es dabei zu einer Verletzung der lokalen Invarianz kommen. Skizze \ref{fig:rbt_balance}
veranschaulicht dabei, welche Fälle auftreten können und wie der rebalancierte Baum aussieht:
\begin{figure}[h!]
\centering
\input{bilder/rbt_balance.tex}
\caption{Die potentiellen Verletzung der lokalen Invarianz nach dem Einfügen und wie sie ausbalanciert werden.}
\label{fig:rbt_balance}
\end{figure}
\paragraph{Suchen in (2-4)-Bäumen}
Mit Hilfe der Hilfsinformationen in den inneren Knoten kann, von der Wurzel
absteigend, der entsprechende Wert gesucht werden. Pro Knoten
benötigt der Suchprozess eine konstante Zeit $\mathcal{O}(1)$. Die gesamte
Laufzeit hängt also direkt von der Höhe des Baumes ab und ist damit $Θ(\log n)$.
Wir starten dabei folgenden Algorithmus mit $\texttt{search\_24}(\texttt{root}(\mathcal{B}_{2,4}), v)$.
\begin{algorithm}[h]
\SetNlSty{texttt}{[}{]}
\caption{\texttt{search\_24}($k, v$)}
\KwIn{A node $k$ and and a data value $v$.}
\KwOut{The node $k'$ of the subtree of $k$ which has $\texttt{data}(k')= v$. an error, if there is no such $k'$.}
\eIf{$α(k)=0$}{
\eIf{$\texttt{data}(k)= v$}{
\KwRet$k$\;
}{
\texttt{error: value not found}\;
}
}{
\uIf{$\texttt{child}_3(k)\neq\texttt{void\_node}$ and $m_2 < v$}{