diff --git a/303_Binaerbaeume.tex b/303_Binaerbaeume.tex index 903a805ee28a8e0118251a27f3b272d139694af7..fbe8239bb8f7d353df63054c48ec13e3fbd0e035 100644 --- a/303_Binaerbaeume.tex +++ b/303_Binaerbaeume.tex @@ -193,6 +193,152 @@ nächstgrößere und nächstkleinere Element finden, solange der Baum nicht allz Alle Funktionen laufen dabei in $\mathcal{O}(h)$, im Idealfall also $\mathcal{O}(\log_2 n)$. Im schlechtesten Fall, in dem der Baum zu einer doppelt verketteten Liste degeneriert ist, liegt die Laufzeit in $\mathcal{O}(n)$. +Um die gängisten Operationen zu beschreiben, adaptieren wir folgende Perspektive auf Binäre Suchbäume: +Ein Binärer Suchbaum über einen Datentyp $D$ mit totaler Ordnung ist entweder leer, oder besteht aus einem linken +Teilbaum, der Information im Node und einem rechten Teilbaum: +\begin{align*} + \text{BST}\; D &= ε\ |\; \text{BST}\; D\quad D\quad \text{BST}\; D \\ + \mathcal{B}\quad &= ε\ |\;\quad l\qquad \ \ \ x\; \ \qquad r +\end{align*} +In dieser Notation beschreiben wir nun kombat die gängisten Operationen auf binären Suchbäumen in rekursiver Form: + +Die Höhe ist $1$ + die Höhe des größeren Teilbaums: +\begin{align*} + \texttt{height}(ε) &= 0 \\ + \texttt{height}(l\; x\; r) &= 1 + \max(\texttt{height}(l), \texttt{height}(r)).\\ +\end{align*} +Gesucht wird analog zur Binärsuche: +\begin{align*} + \texttt{search}(ε,k) &= \texttt{error: Key not found} \\ + \texttt{search}(l\; (k',v')\; r, k) &= + \begin{cases} + \texttt{search}(l, k) &\text{if } k < k'\\ + (k',v') &\text{if } k = k'\\ + \texttt{search}(r, k) &\text{if } k > k'\\ + \end{cases}\\ +\end{align*} +Das Minimum findet man, indem man immer nach links geht: +\begin{align*} + \texttt{min}(ε) &= \texttt{error: Minimum in empty tree ill-defined} \\ + \texttt{min}(ε\; x\; r) &= x \\ + \texttt{min}(l\; x\; r) &= \texttt{min}(l) \\ +\end{align*} + +\paragraph{Einfügen in BST} +Das Einfügen in einen Binären Suchbaum läuft analog zum Suchen - ist der einzufügende Wert größer, so schaut man +rekursiv im rechten Teilbaum, ist er kleiner, im linken. Erst dann, wenn man auf einen leeren Teilbaum stößt, hat man +einen leeren Platz gefunden: +\begin{align*} + \texttt{insert}(ε,(k,v)) &= ε\; (k,v)\; ε \\ + \texttt{insert}(l\; (k',v')\; r, (k,v)) &= + \begin{cases} + \texttt{insert}(l, (k,v))\; (k',v')\; r &\text{if } k < k'\\ + l\; (k,v)]l r &\text{if } k = k'\\ + l\; (k',v')\; \texttt{insert}(r, (k,v)) &\text{if } k > k'\\ + \end{cases}\\ +\end{align*} + + +\paragraph{Löschen aus BST} +Beim Löschen müssen wir unter drei verschiedenen Fällen unterscheiden: Der zu löschende Knoten ist ein Blatt, der zu +löschende Knoten hat genau ein Kind, der zu löschende Knoten hat zwei Kinder. + +\begin{figure}[h!] + \centering + \input{bilder/BST_delete} + \caption{Fallunterscheidung bei der Löschung von $x$: Kein Kind, Ein Kind, zwei Kinder. Der modifizierte Teilbaum $c'$ + ist $c$ ohne \texttt{succ}(x), den Nachfolger von $x$.} + \label{fig:BST_delete} +\end{figure} + +Wir formalisieren es folgendermaßen: +\begin{align*} + \texttt{fad}(ε,x) &= ε \\ + \texttt{fad}(l\; x'\; r, x) &= + \begin{cases} + \texttt{fad}(l,x)\; x'\; r &\text{if } x < x'\\ + \texttt{delete}(l\; x'\; l, x) &\text{if } k = k'\\ + l\; x'\; \texttt{fad}(r,x) &\text{if } x > x'\\ + \end{cases}\\ +\end{align*} +wobei \texttt{delete} nun die drei Fälle in Abbildung \ref{fig:BST_delete} abdeckt: +\begin{align*} + \texttt{delete}(ε\;x\;ε,x) &= ε \\ + \texttt{delete}(ε\;x\;r,x) &= r \\ + \texttt{delete}(l\;x\;ε,x) &= r \\ + \texttt{delete}(l\;x\;r,x) &= l\; t\; \texttt{delete}(r,t) \\ + \text{wobei }\quad t &= \texttt{min}(r) +\end{align*} + + + +\subsection{Die zu erwartende Höhe von BST bei zufälligem Einfügen*} +Ein Binärbaum mit $n$ Elementen kann eine Höhe $h$ zwischen $\ceil{\log_2(n+1)} ≤ h ≤ n$ haben. +Wenn wir einen komplett leeren Binärbaum mit vorgegebenen Daten befüllen, tritt die untere Grenze beispielsweise dann, +wenn wir rekursiv immer wieder den Median der vom Median getrennten Teilarrays einfügen. Die obere Grenze wird z.B. +erreicht, wenn wir die Elemente gemäß ihrer Ordnung einfügen. + +Da die Laufzeit aller Algorithmen auf Binären Suchbäumen direkt von der Höhe abhängt, stellt sich die Frage: +Was ist die zu erwartende Höhe eines Binärbaums, wenn man (eindeutige) Elemente in einer zufälligen Reihenfolge einfügt? + +\begin{proposition} + Werde $π \in S_n$, eine Permutation von $n$ Elementen (d.h. die Elemente $\{1,\cdots,n\}$ in einer zufälligen Reihenfolge + ohne Wiederholungen), in einen initial leeren Binärer Suchbaum eingefügt. Sei $H_n$ die Zufallsvariable, + die die Höhe dieses zufällig befüllten Baumes beschreibt. + Dann wächst der Erwartungswert von $H_n$ logarithmisch, d.h.: + \[ + \mathbb{E}[H_n] \in Θ(\log n). + \] + \label{prop:BST_average_case_wachstum} +\end{proposition} +\begin{proof} + Die untere Grenze ist klar, da wie eingangs beschrieben die Höhe eines Baumes immer in $Ω(\log n)$ liegt. + + In einem Binären Suchbaum sind alle Elemente links vom derzeitigen Knoten kleiner und alle Elemente rechts größer. + Wird ein Element $i$ gezogen, befinden sich am Ende $i-1$ Elemente im linken Teilbaum und $n-i$ + Elemente im rechten Teilbaum. + + Die Höhe eines nichtlehren Baumes ist 1 + die Höhe des größten Teilbauem. + Unter der Annahme, dass alle Elemente gleichwahrscheinlich gezogen werden, ist der Erwartungswert von $H_n$ einfach nur der + Durchschnitt aller möglichen Fälle: + \begin{equation*} + \mathbb{E}[H_n] = \frac{1}{n} \sum_{i=1}^n \mathbb{E}[1 + \max(H_{i-1}, H_{n-i})]. + \label{eq:h_n_rek} + \end{equation*} + + Wir betrachten nun $Y_n = 2^{H_n}$: Wenn wir zeigen können, dass $\mathbb{E}[Y_n] \in \mathcal{O}(n^a)$, so folgt + daraus das $\mathbb{E}[H_n] \in \mathcal{O}(a \log n) = \mathcal{O}(\log n)$. + + In dieser exponentiellen Darstellung wird exponentielle Höhe nun durch \\$Y_n = 2 \max(Y_{i-1},Y_{n-1})$ beschrieben, + analog verhält sich der Erwartungswert von $Y_n$: + \begin{equation*} + \mathbb{E}[Y_n] = \frac{2}{n} \sum_{i=1}^n \mathbb{E}[\max(Y_{i-1}, Y_{n-i})]. + \label{eq:EW_Yn_1} + \end{equation*} + Wobei wir durch die Abschätzung $\mathbb{E}[\max(X,Y)] ≤ \mathbb{E}[X] + \mathbb{E}[Y]$ (gültig für nichtnegative + Zufallsvariablen $X$ und $Y$) und der Symmetrie der Summenterme weiter zu + \[ + \mathbb{E}[Y_n] ≤ \frac{2}{n} \sum_{i=1}^n (\mathbb{E}[Y_{i-1}] + \mathbb{E}[Y_{n-i}]) = \frac{4}{n} + \sum_{i=0}^{n-1}\mathbb{E}[ Y_i ] + \] + vereinfachen. + + Setzte $Z_n = \mathbb{E}[Y_n]$, die resultierende Rekurrenzformel lässt sich wie folgt umstellen: + \begin{align*} + Z_n &= \frac{4}{n} \sum_{i=0}^{n-1} Z_i \\ + &= \frac{4}{n} (Z_{n-1} + Z_{n-2} + \cdots + Z_0) \\ + &= \frac{4}{n} (Z_{n-1} + \frac{n-1}{4} Z_{n-1}) \\ + &= \frac{4}{n} (1+\frac{n-1}{4}) Z_{n-1} \\ + &= \frac{4 + n -1}{n} Z_{n-1} \\ + &= \frac{3+n}{n} Z_{n-1}, + \end{align*} + welche die Lösung $Z_n = c \cdot (n+3)(n+2)(n+1) \in \mathcal{O}(n^3)$ besitzt. Da + \[ + \log n^3 = 3 \log n \in \mathcal{O}(\log n), + \] + gilt $\mathbb{E}[H_n] \in \mathcal{O}(\log n)$. +\end{proof} + \paragraph{Suchen in Binärbäumen:} Der Algorithmus ähnelt einer Binärsuche. diff --git a/bilder/BST_delete.tex b/bilder/BST_delete.tex new file mode 100644 index 0000000000000000000000000000000000000000..dbee0590945c8512e6bbc528ba437345ba4ae7d2 --- /dev/null +++ b/bilder/BST_delete.tex @@ -0,0 +1,68 @@ +\tikzsetnextfilename{BST_delete} +\begin{tikzpicture}[ + treenode/.style = {align=center,inner sep=0pt, text centered, font=\sffamily}, + fullnode/.style = {treenode, circle, draw, text width=1.5em}, + subtree/.style = {treenode, circle, text width=1.5em}, + level/.style={sibling distance = 5cm/#1, + level distance = 1.5cm}, + scale=0.4 + ] + \begin{scope} [local bounding box=fall1] % case 1 + \begin{scope}[local bounding box=f1v] + \node[fullnode] (x) {$x$} + child{ node [subtree] (lε) {$ε$}} + child{ node [subtree] (rε) {$ε$}} + ; + \end{scope} + \begin{scope}[shift={(6,-0.8)}, local bounding box=f1n] + \node[subtree] (tε) {$ε$}; + \end{scope} + \draw [->,decorate,decoration={snake,amplitude=.3mm,segment length=2mm,post length=1mm}] (f1v) -- node[below]{\tiny \texttt{delete}} (f1n); + \end{scope} + + \begin{scope} [shift={(14,0.80)}, local bounding box=fall2] % case 2 + \begin{scope}[local bounding box=f2v] + \node[fullnode] (x) {$x$} + child{ node [subtree] (lε) {$ε$}} + child{ node [fullnode] (ry) {$y$} + child{ node [subtree] (la) {$a$}} + child{ node [subtree] (rb) {$b$}}} + ; + \end{scope} + \begin{scope}[shift={(10,-0.7)}, local bounding box=f2n] + \node[fullnode] (ty) {$y$} + child{ node [subtree] (la) {$a$}} + child{ node [subtree] (rb) {$b$}} + + ; + \end{scope} + \draw [->,decorate,decoration={snake,amplitude=.3mm,segment length=2mm,post length=1mm}] (f2v) -- node[below]{\tiny \texttt{delete}} (f2n); + \end{scope} + + + \begin{scope} [shift={(7,-6)}, local bounding box=fall3] % case 3 + \begin{scope}[local bounding box=f3v] + \node[fullnode] (x) {$x$} + child{ node [fullnode] (ry) {$y$} + child{ node [subtree] (la) {$a$}} + child{ node [subtree] (rb) {$b$}}} + child{ node [fullnode] (lz) {$z$} + child{ node [subtree] (lc) {$c$}} + child{ node [subtree] (rd) {$d$}}} + ; + \end{scope} + \begin{scope}[shift={(11,-0)}, local bounding box=f3n] + \node[fullnode] (ty) {$\texttt{succ}(x)$} + child{ node [fullnode] (ry) {$y$} + child{ node [subtree] (la) {$a$}} + child{ node [subtree] (rb) {$b$}}} + child{ node [fullnode] (lz) {$z$} + child{ node [subtree] (lc') {$c'$}} + child{ node [subtree] (rd) {$d$}}} + ; + \end{scope} + \draw [->,decorate,decoration={snake,amplitude=.3mm,segment length=2mm,post length=1mm}] (f3v) -- node[below]{\tiny \texttt{delete}} (f3n); + \end{scope} + + +\end{tikzpicture}