Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
Datenstrukturen und Algorithm Skript
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Cemal, Mevludin
Datenstrukturen und Algorithm Skript
Commits
bec75ae9
Commit
bec75ae9
authored
3 years ago
by
Florian Unger
Browse files
Options
Downloads
Patches
Plain Diff
alten node-orientierten code in appendix verschoben
parent
968821ca
No related branches found
No related tags found
No related merge requests found
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
303_Binaerbaeume.tex
+0
-133
0 additions, 133 deletions
303_Binaerbaeume.tex
902_Appendix_BST.tex
+136
-0
136 additions, 0 deletions
902_Appendix_BST.tex
with
136 additions
and
133 deletions
303_Binaerbaeume.tex
+
0
−
133
View file @
bec75ae9
...
...
@@ -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}
This diff is collapsed.
Click to expand it.
902_Appendix_BST.tex
0 → 100644
+
136
−
0
View file @
bec75ae9
\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}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment