Skip to content
Snippets Groups Projects
Commit 2f36051e authored by Florian Unger's avatar Florian Unger
Browse files

kapitel 1.4 semi-finalized

parent 6e011a77
Branches
Tags
No related merge requests found
...@@ -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.
\subsubsection{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.
\subsubsection{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 also $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)$.
\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
......
...@@ -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}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment