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
Unger, Florian Fedor Fridolin
Datenstrukturen und Algorithm Skript
Commits
2f36051e
Commit
2f36051e
authored
5 years ago
by
Florian Unger
Browse files
Options
Downloads
Patches
Plain Diff
kapitel 1.4 semi-finalized
parent
6e011a77
Branches
Branches containing commit
Tags
Tags containing commit
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
104_Rekursionen.tex
+17
-14
17 additions, 14 deletions
104_Rekursionen.tex
201_quicksort.tex
+3
-7
3 additions, 7 deletions
201_quicksort.tex
Datenstrukturen_und_Algorithmen.tex
+3
-1
3 additions, 1 deletion
Datenstrukturen_und_Algorithmen.tex
with
23 additions
and
22 deletions
104_Rekursionen.tex
+
17
−
14
View file @
2f36051e
...
@@ -16,8 +16,7 @@ Laufzeitfunktionen finden und ihre Komplexitätsklasse bestimmen.
...
@@ -16,8 +16,7 @@ Laufzeitfunktionen finden und ihre Komplexitätsklasse bestimmen.
Allerdings kann es auch vorkommen, dass eine (naive) rekursive Lösung deutlich langsamer läuft und mehr Speicher
Allerdings kann es auch vorkommen, dass eine (naive) rekursive Lösung deutlich langsamer läuft und mehr Speicher
benötigt.
benötigt.
\subsection
{
Beispiele
}
\subsection
{
Die Fakultätsfunktion
$
n
!
$}
\subsubsection
{
Die Fakultätsfunktion
$
n
!
$}
Wir berechnen
$
\cdot
!
:
\mathbb
{
N
}
\rightarrow
\mathbb
{
N
}$
.
Wir berechnen
$
\cdot
!
:
\mathbb
{
N
}
\rightarrow
\mathbb
{
N
}$
.
\begin{minipage}
[t]
{
0.4
\textwidth
}
\begin{minipage}
[t]
{
0.4
\textwidth
}
...
@@ -87,7 +86,7 @@ sodass bei ihrem Einsatz Speicherverbrauch/Geschwindigkeit eigentlich kein aussc
...
@@ -87,7 +86,7 @@ sodass bei ihrem Einsatz Speicherverbrauch/Geschwindigkeit eigentlich kein aussc
Momentan (Stand 2020) führen beispielsweise Haskell und Scala solche Umwandlungen durch, während beispielsweise C,
Momentan (Stand 2020) führen beispielsweise Haskell und Scala solche Umwandlungen durch, während beispielsweise C,
Java, Python mit call stacks arbeiten.
Java, Python mit call stacks arbeiten.
\subs
ubs
ection
{
Die Fibonacci-Zahlen
$
\text
{
fib
}
(
n
)
$}
\subsection
{
Die Fibonacci-Zahlen
$
\text
{
fib
}
(
n
)
$}
Wir berechnen die Fibonacci-Zahlen durch die Funktion
$
\text
{
fib
}
:
\mathbb
{
N
}
\rightarrow
\mathbb
{
N
}$
, welche wie folgt definiert ist:
Wir berechnen die Fibonacci-Zahlen durch die Funktion
$
\text
{
fib
}
:
\mathbb
{
N
}
\rightarrow
\mathbb
{
N
}$
, welche wie folgt definiert ist:
$
\text
{
fib
}
(
n
)
:
=
\text
{
fib
}
(
n
-
1
)
+
\text
{
fib
}
(
n
-
2
)
$
.
$
\text
{
fib
}
(
n
)
:
=
\text
{
fib
}
(
n
-
1
)
+
\text
{
fib
}
(
n
-
2
)
$
.
...
@@ -132,7 +131,7 @@ zudem $\mathcal{O}(2^n)$ (Breitensuche) oder auch ``nur'' $\mathcal{O}(n)$ (Tief
...
@@ -132,7 +131,7 @@ zudem $\mathcal{O}(2^n)$ (Breitensuche) oder auch ``nur'' $\mathcal{O}(n)$ (Tief
Auch funktionale Sprachen haben hier keine wirklich Hebel, die Laufzeit zu verbessern. Diese naive Implementierung ist
Auch funktionale Sprachen haben hier keine wirklich Hebel, die Laufzeit zu verbessern. Diese naive Implementierung ist
somit leider für größere
$
n
$
unbrauchbar. Selbst eine moderne CPU berechnet
$
\texttt
{
fibrec
}
(
1000
)
$
nichtmehr in unserer Lebenszeit.
somit leider für größere
$
n
$
unbrauchbar. Selbst eine moderne CPU berechnet
$
\texttt
{
fibrec
}
(
1000
)
$
nichtmehr in unserer Lebenszeit.
\subsubsection
{
Die Türme von Hanoi
}
\subsubsection
{
Die Türme von Hanoi
*
}
Ein weiteres klassisches Problem sind die Türme von Hanoi. Wir haben folgende Spielregeln:
Ein weiteres klassisches Problem sind die Türme von Hanoi. Wir haben folgende Spielregeln:
\begin{itemize}
\begin{itemize}
\item
$
3
$
Stäbe
$
A, B
$
und
$
C
$
.
\item
$
3
$
Stäbe
$
A, B
$
und
$
C
$
.
...
@@ -142,9 +141,9 @@ Ein weiteres klassisches Problem sind die Türme von Hanoi. Wir haben folgende S
...
@@ -142,9 +141,9 @@ Ein weiteres klassisches Problem sind die Türme von Hanoi. Wir haben folgende S
\item
Es darf nie eine größere auf einer kleineren Scheibe liegen.
\item
Es darf nie eine größere auf einer kleineren Scheibe liegen.
\end{itemize}
\end{itemize}
TODO:
Kommt das überhaupt dran?
TODO:
Wird noch ausgeführt. Oder eine Übungsaufgabe.
\subs
ubs
ection
{
Binärsuche
}
\subsection
{
Binärsuche
}
Ein sehr praxisnahes Beispiel für Rekursion ist die Binärsuche auf sortierten Arrays. Wir suchen in einem sortierten
Ein sehr praxisnahes Beispiel für Rekursion ist die Binärsuche auf sortierten Arrays. Wir suchen in einem sortierten
Array, welches Objekte enthält, die nach dem Schlüssel
$
k
$
sortiert sind, das Objekt mit dem Schlüssel
$
k
_
0
$
.
Array, welches Objekte enthält, die nach dem Schlüssel
$
k
$
sortiert sind, das Objekt mit dem Schlüssel
$
k
_
0
$
.
Die Funktion
$
\texttt
{
key
}
(
x
)
$
verrät uns hierbei den Schlüssel eines Objekts
$
x
$
. Wir nehmen dabei an, dass das
Die Funktion
$
\texttt
{
key
}
(
x
)
$
verrät uns hierbei den Schlüssel eines Objekts
$
x
$
. Wir nehmen dabei an, dass das
...
@@ -156,10 +155,10 @@ gesuchte Objekt existiert.
...
@@ -156,10 +155,10 @@ gesuchte Objekt existiert.
\KwOut
{
Das Objekt mit dem Schlüssel
$
k
_
0
$}
\KwOut
{
Das Objekt mit dem Schlüssel
$
k
_
0
$}
\caption
{
\texttt
{
binsearchrec
}}
\caption
{
\texttt
{
binsearchrec
}}
$
m
\leftarrow
\floor
{
\frac
{
\texttt
{
len
}
(
\mathcal
{
A
}
)
}{
2
}}$
\;
$
m
\leftarrow
\floor
{
\frac
{
\texttt
{
len
}
(
\mathcal
{
A
}
)
}{
2
}}$
\;
\uIf
{$
\texttt
{
key
}
(
\mathcal
{
A
}
[
m
])
> k
_
0
$}{
\uIf
{$
\
emph
{
\
texttt
{
key
}
}
(
\mathcal
{
A
}
[
m
])
> k
_
0
$}{
return
$
\texttt
{
binsearchrec
}
(
\mathcal
{
A
}
[
0
,
\dots
,m
])
$
\;
return
$
\texttt
{
binsearchrec
}
(
\mathcal
{
A
}
[
0
,
\dots
,m
])
$
\;
}
}
\ElseIf
{$
\texttt
{
key
}
(
\mathcal
{
A
}
[
m
])
< k
_
0
$}{
\ElseIf
{$
\
emph
{
\
texttt
{
key
}
}
(
\mathcal
{
A
}
[
m
])
< k
_
0
$}{
return
$
\texttt
{
binsearchrec
}
(
\mathcal
{
A
}
[
m
+
1
,
\dots
,
\texttt
{
len
}
(
\mathcal
{
A
}
)])
$
\;
return
$
\texttt
{
binsearchrec
}
(
\mathcal
{
A
}
[
m
+
1
,
\dots
,
\texttt
{
len
}
(
\mathcal
{
A
}
)])
$
\;
}
}
\Else
{
\Else
{
...
@@ -171,10 +170,10 @@ Machen wir zuerst eine Aufwandsanalyse per Hand, bevor wir im nächsten Kapitel
...
@@ -171,10 +170,10 @@ Machen wir zuerst eine Aufwandsanalyse per Hand, bevor wir im nächsten Kapitel
Die Laufzeit von
\texttt
{
binsearchrec
}
hat Unterschiede im best-case oder worst-case Szenario. Best-case wäre, wenn wir
Die Laufzeit von
\texttt
{
binsearchrec
}
hat Unterschiede im best-case oder worst-case Szenario. Best-case wäre, wenn wir
schon beim ersten Aufruf zufällig unser gesuchtes Element finden (Aufwand
$
f
\in
\mathcal
{
O
}
(
1
)
$
).
schon beim ersten Aufruf zufällig unser gesuchtes Element finden (Aufwand
$
f
\in
\mathcal
{
O
}
(
1
)
$
).
Im pessimistischen Fall teilen wir unser Array so lange, bis nur noch ein Element
übrig bleibt (nach Annahme ist es dann
Im pessimistischen Fall teilen wir unser Array so lange, bis nur noch ein Element
, das Gesuchte, übrig bleibt.
das gesuchte).
Würden wir auch die Suche nach nicht-enthaltenen Schlüsseln erlauben, wären wir auch
automatisch
immer im
Würden wir auch die Suche nach nicht-enthaltenen Schlüsseln erlauben, wären wir auch immer im
worst-case. Betrachten wir hier als
$
T
(
n
)
=
T
_{
\text
{
worst
}}^{
\texttt
{
binsearchrec
}}$
. Ein Durchlauf von
worst-case. Betrachten wir hier als
o
$
T
(
n
)
=
T
_{
\text
{
worst
}}^{
\texttt
{
binsearchrec
}}$
. Ein Durchlauf von
$
\texttt
{
binsearchrec
}$
hat dabei Aufwand
$
f
\in
\mathcal
{
O
}
(
1
)
$
.
$
\texttt
{
binsearchrec
}$
hat dabei Aufwand
$
f
\in
\mathcal
{
O
}
(
1
)
$
sowie den Aufwand rekursiver Aufrufe
.
\begin{align*}
\begin{align*}
T(n)
&
= f(n) + T(
\floor
{
\frac
{
n
}{
2
}}
)
\\
T(n)
&
= f(n) + T(
\floor
{
\frac
{
n
}{
2
}}
)
\\
...
@@ -184,7 +183,7 @@ $\texttt{binsearchrec}$ hat dabei Aufwand $f \in \mathcal{O}(1)$.
...
@@ -184,7 +183,7 @@ $\texttt{binsearchrec}$ hat dabei Aufwand $f \in \mathcal{O}(1)$.
&
\leq
\log
_
2(n) f(n)
\in
\mathcal
{
O
}
(
\ln
(n))
&
\leq
\log
_
2(n) f(n)
\in
\mathcal
{
O
}
(
\ln
(n))
\end{align*}
\end{align*}
Der asymptotische Aufwand liegt
in
$
T
^{
\texttt
{
binsearchrec
}}
\in
\mathcal
{
O
}
(
\log
{
n
}
)
$
, siehe Hauptsatz der
Der asymptotische Aufwand liegt
damit in
$
T
_{
\text
{
worst
}}
^{
\texttt
{
binsearchrec
}}
\in
\mathcal
{
O
}
(
\log
{
n
}
)
$
, siehe Hauptsatz der
Laufzeitfunktionen. Damit ist überhaupt erst die Motivation für Sortieralgorithmen gegeben: Suchen in sortierten Arrays
Laufzeitfunktionen. Damit ist überhaupt erst die Motivation für Sortieralgorithmen gegeben: Suchen in sortierten Arrays
geht verdammt schnell.
geht verdammt schnell.
...
@@ -235,5 +234,9 @@ Greift keiner der drei Fälle, so muss die Laufzeit anders bestimmt werden. Insb
...
@@ -235,5 +234,9 @@ Greift keiner der drei Fälle, so muss die Laufzeit anders bestimmt werden. Insb
$
\texttt
{
fibrec
}$
lassen sich nicht mit dem Hauptsatz der Laufzeitfunktionen behandeln, da ihre Teilprobleme kein
$
\texttt
{
fibrec
}$
lassen sich nicht mit dem Hauptsatz der Laufzeitfunktionen behandeln, da ihre Teilprobleme kein
Bruchteil
$
\frac
{
n
}{
b
}$
des Hauptproblems sind.
Bruchteil
$
\frac
{
n
}{
b
}$
des Hauptproblems sind.
Wir untersuchen nun als Beispiel die asymptotische Laufzeit von
Wir untersuchen nun als Beispiel die asymptotische Laufzeit von
$
\texttt
{
binsearchrec
}$
noch einmal. Wir haben pro
Rekursionsschritt ein (
$
a
=
1
)
$
halb so großes Unterproblem (
$
b
=
2
$
), damit also
$
\log
_
b a
=
0
$
. Die konstante Funktion
$
f
$
liegt für ein
$
ε
\in
\mathbb
{
R
}^
+
$
gerade nichtmehr in
$
\mathcal
{
O
}
(
n
^{
log
_
b
(
a
)
-
ε
}
)
$
, aber definitv in
$
\mathcal
{
O
}
(
n
^{
\log
_
b a
}
)
=
\mathcal
{
O
}
(
n
^
0
)
$
, also haben wir den zweiten Fall und unser Aufwand liegt in
$
Θ
(
n
^{
\log
_
b
a
}
\log
n
)
=
Θ
(
\log
n
)
$
.
This diff is collapsed.
Click to expand it.
201_quicksort.tex
+
3
−
7
View file @
2f36051e
\section
{
Quicksort
}
\section
{
Quicksort
}
Quicksort ist einer der meist verwendeten Sortieralgorithmen. Die Kernidee ist wieder das divide-et-impera-Prinzip.
Quicksort ist einer der meist verwendeten Sortieralgorithmen. Die Idee ist wieder das divide-et-impera-Prinzipr,
Der Kern des Algorithmus ist die Zerlegung des Arrays, die sogenannte Partition.
der Kern des Algorithmus ist die Zerlegung des Arrays, die sogenannte Partition.
%\begin{center}
%\includegraphics[bb=0cm 0bp 1059bp 324bp,scale=0.2]{bilder/quick}
%\par\end{center}
\subsection
{
Partition
}
\subsection
{
Partition
}
Für eine Partition eines Arrays
$
\mathcal
{
A
}$
wählen wir zuerst ein Pivotelement
$
p
$
. Nun sortieren wir das Array so,
Für eine Partition eines Arrays
$
\mathcal
{
A
}$
wählen wir zuerst ein Pivotelement
$
p
$
. Nun sortieren wir das Array so,
...
@@ -76,7 +72,7 @@ Sei der Einfachheit halber $n = 2^{k'}$ für ein $k' \in \mathbb{N}$.
...
@@ -76,7 +72,7 @@ Sei der Einfachheit halber $n = 2^{k'}$ für ein $k' \in \mathbb{N}$.
&
=
\ldots
\\
&
=
\ldots
\\
&
= nT
_{
\text
{
qs
}}^{
\text
{
best
}}
(1) +
\sum
_{
k=0
}^{
\log
_
2(n)
}
2
^
k T
_{
\text
{
p
}}^{
\text
{
best
}}
\left
(
\frac
{
n
}{
2
^
k
}
\right
)
\\
&
= nT
_{
\text
{
qs
}}^{
\text
{
best
}}
(1) +
\sum
_{
k=0
}^{
\log
_
2(n)
}
2
^
k T
_{
\text
{
p
}}^{
\text
{
best
}}
\left
(
\frac
{
n
}{
2
^
k
}
\right
)
\\
\end{align*}
\end{align*}
Wir sehen nun in einer Nebenrechnung, dass
$
n
\mapsto
2
^
k T
_{
\text
{
p
}
(
\frac
{
n
}{
2
^
k
}
)
}
\in
\Theta
(
n
)
$
für alle
Wir sehen nun in einer Nebenrechnung, dass
$
n
\mapsto
2
^
k T
_{
\text
{
p
}
}
(
\frac
{
n
}{
2
^
k
}
)
\in
\Theta
(
n
)
$
für alle
$
k
\in
\mathbb
{
N
}$
.
$
k
\in
\mathbb
{
N
}$
.
Sei also
$
k
$
fixiert. Dann gilt
$
c
_
1
\floor
{
\frac
{
n
}{
2
^
k
}}
\leq
T
_{
\text
{
p
}}
(
\floor
{
\frac
{
n
}{
2
^
k
}}
)
\leq
c
_
2
Sei also
$
k
$
fixiert. Dann gilt
$
c
_
1
\floor
{
\frac
{
n
}{
2
^
k
}}
\leq
T
_{
\text
{
p
}}
(
\floor
{
\frac
{
n
}{
2
^
k
}}
)
\leq
c
_
2
\ceil
{
\frac
{
n
}{
2
^
k
}}$
für alle
$
n
\geq
n
_
0
2
^
k
$
, wobei
$
n
_
0
$
durch
$
T
_{
\text
{
p
}}
\in
\Theta
(
n
)
$
gegeben ist. Wir
\ceil
{
\frac
{
n
}{
2
^
k
}}$
für alle
$
n
\geq
n
_
0
2
^
k
$
, wobei
$
n
_
0
$
durch
$
T
_{
\text
{
p
}}
\in
\Theta
(
n
)
$
gegeben ist. Wir
...
...
This diff is collapsed.
Click to expand it.
Datenstrukturen_und_Algorithmen.tex
+
3
−
1
View file @
2f36051e
...
@@ -2,6 +2,8 @@
...
@@ -2,6 +2,8 @@
\usepackage
[ngerman]
{
babel
}
\usepackage
[ngerman]
{
babel
}
%encoding
%encoding
\usepackage
[utf8]
{
inputenc
}
\usepackage
[utf8]
{
inputenc
}
\usepackage
{
alphabeta
}
%math symbols
%math symbols
\usepackage
{
amsmath
}
\usepackage
{
amsmath
}
...
@@ -56,6 +58,6 @@
...
@@ -56,6 +58,6 @@
\tableofcontents
\tableofcontents
\input
{
100
_
Grundlagen
}
\input
{
100
_
Grundlagen
}
%
\input{200_Sortieralgorithmen}
\input
{
200
_
Sortieralgorithmen
}
%\input{300_Datenstrukturen}
%\input{300_Datenstrukturen}
\end{document}
\end{document}
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