diff --git a/303_Binaerbaeume.tex b/303_Binaerbaeume.tex index fbe8239bb8f7d353df63054c48ec13e3fbd0e035..bb16e19c542b417cdb920ffd2e4aaae521d2d0e8 100644 --- a/303_Binaerbaeume.tex +++ b/303_Binaerbaeume.tex @@ -339,136 +339,3 @@ Was ist die zu erwartende Höhe eines Binärbaums, wenn man (eindeutige) Element gilt $\mathbb{E}[H_n] \in \mathcal{O}(\log n)$. \end{proof} - -\paragraph{Suchen in Binärbäumen:} -Der Algorithmus ähnelt einer Binärsuche. - -\begin{algorithm}[H] - \SetNlSty{texttt}{[}{]} - \caption{\texttt{search}($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$} - \eIf{$k \neq \texttt{void\_node}$ and $\texttt{data}(k) \neq \texttt{void}$}{ - \KwRet $k$ \; - }{ - \eIf{$v \leq \texttt{data}(k)$}{ - $\texttt{search}(\texttt{left}(k), v)$ \; - }{ - $\texttt{search}(\texttt{right}(k), v)$ \; - } - } -\end{algorithm} - -\paragraph{Finden des Minimums und Maximums in $\mathcal{B}$} -Hier gehen wir so lange nach links, bis es kein linkes Kind mehr gibt. Da wir nach symmetrischer Reihenfolge geordnet -sind, finden wir damit das Minimum des Baums, wenn wir $\texttt{minimum}(\texttt{root}(\mathcal{B}))$ aufrufen. - -\begin{algorithm}[H] - \SetNlSty{texttt}{[}{]} - \caption{\texttt{minimum}($k$)} - \KwIn{A node $k$ of a binary search tree} - \KwOut{The node with the smallest value within the subtree of $k$} - \eIf{$\texttt{left}(k)$ = \texttt{void\_node}}{ - \KwRet $k$ \; - }{ - \KwRet $\texttt{minimum}(\texttt{left}(k))$ \; - } -\end{algorithm} - -Diese Rekursion ist eine Endrekursion und braucht keinen zusätzlichen Speicher. Die Laufzeit ist von -$\mathcal{O}(h)$ begrenzt. - -Analog finden wir das Maximum mit $\texttt{maximum}(\texttt{root}(\mathcal{B}))$ wenn wir immer nach rechts laufen. - -\paragraph{Finden des Vorgängers/Nachfolgers eines Knotens:} -Übungsaufgabe. - -\paragraph{Einfügen in den Binärbaum:} - -In den Binärbaum $B$ wird der Wert $w$ eingefügt. Wir müssen dabei darauf achten, dass der Wert an der passenden Stelle -eingefügt wird, also der Baum in symmetrische Reihenfolge weiterhin sortiert bleibt. -Wir gehen also immer dann nach links, wenn der Wert im Knoten größer ist und andernfalls rechts entlang. - -\begin{algorithm}[H] - \SetArgSty{textrm} - \SetNlSty{texttt}{[}{]} - \caption{\texttt{insert}($B, v$)} - \KwIn{A binary tree $\mathcal{B}$ and a new value $v$} - \KwOut{Side effects in $\mathcal{M}$} - $x_\text{last} \leftarrow \texttt{void\_node}$ \; - $x \leftarrow \texttt{root}(\mathcal{B})$ \; - \While{$x \neq \texttt{void\_node}$}{ - $x_\text{last} \leftarrow x$ \; - \eIf{$v < \texttt{data}(x)$}{ - $x \leftarrow \texttt{left}(x)$ \; - }{ - $x \leftarrow \texttt{right}(x)$ \; - } - } - %TODO: void_node nicht länger als leeren Knoten missbrauchen - $\texttt{data}(x) \leftarrow v$ \; - $\texttt{parent}(x) \leftarrow x_\text{last}$ \; - $\texttt{change\_parents\_reference}(\mathcal{B}, x, x)$ \; -\end{algorithm} - -Wobei folgende Hilfsfunktion den richtigen Kindpointer von einem alten Kindknoten auf einen neuen umbiegt. In unserem -Fall benutzten wir sie nur, um eine Referenz von $\texttt{parent}(x)$ auf $x$ zu legen. - - -\begin{algorithm}[H] - \SetNlSty{texttt}{[}{]} - \caption{$\texttt{change\_parents\_reference}(B, k, t)$} - \KwIn{A binary tree $\mathcal{B}$, the old child node $k$ and the new target child node~$t$} - \KwOut{Side effects in $\mathcal{B}$: The parent of $k$ changes the respective child pointer from $k$ to $t$. In case - of $k$ being the root, $t$ is set as the new root.} - $p \leftarrow \texttt{parent}(k)$ \; - \uIf{$p = \texttt{void\_node}$}{ - $\texttt{root}(\mathcal{B}) \leftarrow t$ \; - } - \uElseIf{$\texttt{data}(k) < \texttt{data}(p)$}{ - $\texttt{left}(p) \leftarrow t$ \; - } - \Else{ - $\texttt{right}(p) \leftarrow t$ \; - } -\end{algorithm} - -\paragraph{Löschen eines Werts:} - -Soll der Knoten $k$ gelöscht werden, müssen drei Fälle unterschieden werden, damit die Sortierung erhalten bleibt: -\begin{enumerate} - \item Ist $k$ kinderlos, so entfernen wird den Knoten, indem wir an der passenden Stelle des Elternknotens die - Referenz auf $\texttt{void}$ umschreiben. - \item Hat $k$ hat nur ein Kind, $c$, so entfernen wir den Knoten $k$ indem wir $k$ überspringen. Dazu biegen wir - die Referenz des Elternknotens von $k$ auf das Kind von $c$ um. - \item Im letzten Fall hat $k$ hat zwei Kinder. Wir ersetzen die Daten von $k$ durch die Daten des nächstgrößeren - Knotens $t$ und löschen dann den Knoten $t$. Da dieser nur maximal ein Kind hat (er kann kein linkes Kind haben, - sonst wäre dass das nächstgrößere) terminert dieser rekursive Aufruf von $\texttt{delete}$ nach einem Schritt, da - wir einem der letzten beiden Fälle landen. Ist das Verschieben der Daten sehr teuer, so können wir alternativ auch - alle Pointer so umbiegen, dass $t$ in der Baumstruktur den Platz von $k$ einnimmt (nicht gezeigt). -\end{enumerate} - -\begin{algorithm}[H] - \SetArgSty{textrm} - \SetNlSty{texttt}{[}{]} - \caption{\texttt{delete}($\mathcal{B}, k$)} - \KwIn{A binary tree $\mathcal{B}$ and the unwanted node $k$} - \KwOut{Side effects in $\mathcal{M}$: The node $k$ is removed from $\mathcal{B}$, but child nodes of $k$ are - preserved.} - \uIf{$\texttt{left}(k) = \texttt{void\_node} \text{ and } \texttt{right}(k) = \texttt{void\_node}$}{ - $\texttt{change\_parents\_reference}(\mathcal{B}, k, \texttt{void\_node})$ \; - } - \uElseIf{$\texttt{left}(k) \neq \texttt{void\_node} \text{ XOR } \texttt{right}(k) \neq \texttt{void\_node}$}{ - \eIf{$\texttt{left}(k) \neq \texttt{void\_node}$}{ - $c \leftarrow \texttt{left}(k)$ \; - }{ - $c \leftarrow \texttt{right}(k)$ \; - } - $\texttt{change\_parents\_reference}(\mathcal{B}, k, c)$ \; - } - \Else{ - $t \leftarrow \texttt{minimum}(\texttt{right}(k))$ \; - $\texttt{data}(k) \leftarrow \texttt{data}(t)$ \; - $\texttt{delete}(\mathcal{B}, t)$ \; - } -\end{algorithm} diff --git a/902_Appendix_BST.tex b/902_Appendix_BST.tex new file mode 100644 index 0000000000000000000000000000000000000000..1c8af8fd11e6bec3bcbb9ba15e0baef626b2502a --- /dev/null +++ b/902_Appendix_BST.tex @@ -0,0 +1,136 @@ +\chapter{Node-orientierter Pseudocode für BST} +Dieses Kapitel beschreibt die üblichen Operationen von Binary Search Trees in imperativer, node-orientierter Variante. + +\paragraph{Suchen in Binärbäumen:} + +Der Algorithmus ähnelt einer Binärsuche. + +\begin{algorithm}[H] + \SetNlSty{texttt}{[}{]} + \caption{\texttt{search}($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$} + \eIf{$k \neq \texttt{void\_node}$ and $\texttt{data}(k) \neq \texttt{void}$}{ + \KwRet $k$ \; + }{ + \eIf{$v \leq \texttt{data}(k)$}{ + $\texttt{search}(\texttt{left}(k), v)$ \; + }{ + $\texttt{search}(\texttt{right}(k), v)$ \; + } + } +\end{algorithm} + +\paragraph{Finden des Minimums und Maximums in $\mathcal{B}$} +Hier gehen wir so lange nach links, bis es kein linkes Kind mehr gibt. Da wir nach symmetrischer Reihenfolge geordnet +sind, finden wir damit das Minimum des Baums, wenn wir $\texttt{minimum}(\texttt{root}(\mathcal{B}))$ aufrufen. + +\begin{algorithm}[H] + \SetNlSty{texttt}{[}{]} + \caption{\texttt{minimum}($k$)} + \KwIn{A node $k$ of a binary search tree} + \KwOut{The node with the smallest value within the subtree of $k$} + \eIf{$\texttt{left}(k)$ = \texttt{void\_node}}{ + \KwRet $k$ \; + }{ + \KwRet $\texttt{minimum}(\texttt{left}(k))$ \; + } +\end{algorithm} + +Diese Rekursion ist eine Endrekursion und braucht keinen zusätzlichen Speicher. Die Laufzeit ist von +$\mathcal{O}(h)$ begrenzt. + +Analog finden wir das Maximum mit $\texttt{maximum}(\texttt{root}(\mathcal{B}))$ wenn wir immer nach rechts laufen. + +\paragraph{Finden des Vorgängers/Nachfolgers eines Knotens:} +Übungsaufgabe. + +\paragraph{Einfügen in den Binärbaum:} + +In den Binärbaum $B$ wird der Wert $w$ eingefügt. Wir müssen dabei darauf achten, dass der Wert an der passenden Stelle +eingefügt wird, also der Baum in symmetrische Reihenfolge weiterhin sortiert bleibt. +Wir gehen also immer dann nach links, wenn der Wert im Knoten größer ist und andernfalls rechts entlang. + +\begin{algorithm}[H] + \SetArgSty{textrm} + \SetNlSty{texttt}{[}{]} + \caption{\texttt{insert}($B, v$)} + \KwIn{A binary tree $\mathcal{B}$ and a new value $v$} + \KwOut{Side effects in $\mathcal{M}$} + $x_\text{last} \leftarrow \texttt{void\_node}$ \; + $x \leftarrow \texttt{root}(\mathcal{B})$ \; + \While{$x \neq \texttt{void\_node}$}{ + $x_\text{last} \leftarrow x$ \; + \eIf{$v < \texttt{data}(x)$}{ + $x \leftarrow \texttt{left}(x)$ \; + }{ + $x \leftarrow \texttt{right}(x)$ \; + } + } + %TODO: void_node nicht länger als leeren Knoten missbrauchen + $\texttt{data}(x) \leftarrow v$ \; + $\texttt{parent}(x) \leftarrow x_\text{last}$ \; + $\texttt{change\_parents\_reference}(\mathcal{B}, x, x)$ \; +\end{algorithm} + +Wobei folgende Hilfsfunktion den richtigen Kindpointer von einem alten Kindknoten auf einen neuen umbiegt. In unserem +Fall benutzten wir sie nur, um eine Referenz von $\texttt{parent}(x)$ auf $x$ zu legen. + + +\begin{algorithm}[H] + \SetNlSty{texttt}{[}{]} + \caption{$\texttt{change\_parents\_reference}(B, k, t)$} + \KwIn{A binary tree $\mathcal{B}$, the old child node $k$ and the new target child node~$t$} + \KwOut{Side effects in $\mathcal{B}$: The parent of $k$ changes the respective child pointer from $k$ to $t$. In case + of $k$ being the root, $t$ is set as the new root.} + $p \leftarrow \texttt{parent}(k)$ \; + \uIf{$p = \texttt{void\_node}$}{ + $\texttt{root}(\mathcal{B}) \leftarrow t$ \; + } + \uElseIf{$\texttt{data}(k) < \texttt{data}(p)$}{ + $\texttt{left}(p) \leftarrow t$ \; + } + \Else{ + $\texttt{right}(p) \leftarrow t$ \; + } +\end{algorithm} + +\paragraph{Löschen eines Werts:} + +Soll der Knoten $k$ gelöscht werden, müssen drei Fälle unterschieden werden, damit die Sortierung erhalten bleibt: +\begin{enumerate} + \item Ist $k$ kinderlos, so entfernen wird den Knoten, indem wir an der passenden Stelle des Elternknotens die + Referenz auf $\texttt{void}$ umschreiben. + \item Hat $k$ hat nur ein Kind, $c$, so entfernen wir den Knoten $k$ indem wir $k$ überspringen. Dazu biegen wir + die Referenz des Elternknotens von $k$ auf das Kind von $c$ um. + \item Im letzten Fall hat $k$ hat zwei Kinder. Wir ersetzen die Daten von $k$ durch die Daten des nächstgrößeren + Knotens $t$ und löschen dann den Knoten $t$. Da dieser nur maximal ein Kind hat (er kann kein linkes Kind haben, + sonst wäre dass das nächstgrößere) terminert dieser rekursive Aufruf von $\texttt{delete}$ nach einem Schritt, da + wir einem der letzten beiden Fälle landen. Ist das Verschieben der Daten sehr teuer, so können wir alternativ auch + alle Pointer so umbiegen, dass $t$ in der Baumstruktur den Platz von $k$ einnimmt (nicht gezeigt). +\end{enumerate} + +\begin{algorithm}[H] + \SetArgSty{textrm} + \SetNlSty{texttt}{[}{]} + \caption{\texttt{delete}($\mathcal{B}, k$)} + \KwIn{A binary tree $\mathcal{B}$ and the unwanted node $k$} + \KwOut{Side effects in $\mathcal{M}$: The node $k$ is removed from $\mathcal{B}$, but child nodes of $k$ are + preserved.} + \uIf{$\texttt{left}(k) = \texttt{void\_node} \text{ and } \texttt{right}(k) = \texttt{void\_node}$}{ + $\texttt{change\_parents\_reference}(\mathcal{B}, k, \texttt{void\_node})$ \; + } + \uElseIf{$\texttt{left}(k) \neq \texttt{void\_node} \text{ XOR } \texttt{right}(k) \neq \texttt{void\_node}$}{ + \eIf{$\texttt{left}(k) \neq \texttt{void\_node}$}{ + $c \leftarrow \texttt{left}(k)$ \; + }{ + $c \leftarrow \texttt{right}(k)$ \; + } + $\texttt{change\_parents\_reference}(\mathcal{B}, k, c)$ \; + } + \Else{ + $t \leftarrow \texttt{minimum}(\texttt{right}(k))$ \; + $\texttt{data}(k) \leftarrow \texttt{data}(t)$ \; + $\texttt{delete}(\mathcal{B}, t)$ \; + } +\end{algorithm}