mirror of
https://github.com/MartinThoma/LaTeX-examples.git
synced 2025-04-25 06:18:05 +02:00
Abschnitt über Rekursion hinzugefügt
This commit is contained in:
parent
156a09095a
commit
7e99fea83a
7 changed files with 115 additions and 8 deletions
|
@ -7,3 +7,4 @@ in dem Erstellen dieses Skripts steckt:
|
|||
|01.02.2014 | 14:00 - 14:45 | Thoma | ASCII-Tabelle in C angefangen; Kapitel "Programmiersprachen" hinzugefügt; erste Definitionen
|
||||
|01.02.2014 | 14:45 - 15:30 | Thoma | Haskell angefangen
|
||||
|01.02.2014 | 11:15 - 11:45 | Thoma | Haskell Class Hierachy
|
||||
|01.02.2014 | 16:00 - 17:00 | Thoma | Abschnitt über Rekursion hinzugefügt
|
||||
|
|
|
@ -40,12 +40,7 @@ definiert:
|
|||
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/einfaches-beispiel-klammern.hs}
|
||||
|
||||
\subsection{if / else}
|
||||
Das folgende Beispiel definiert den Binomialkoeffizienten
|
||||
\[\binom{n}{k} := \begin{cases}
|
||||
1 &\text{falls } k=0 \lor k = n\\
|
||||
\binom{n-1}{k-1}+\binom{n-1}{k} &\text{sonst}
|
||||
\end{cases}\]
|
||||
für $n,k \geq 0$:
|
||||
Das folgende Beispiel definiert den Binomialkoeffizienten (vgl. \cref{bsp:binomialkoeffizient})
|
||||
|
||||
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/binomialkoeffizient.hs}
|
||||
\inputminted[numbersep=5pt, tabsize=4]{bash}{scripts/haskell/compile-binom.sh}
|
||||
|
@ -65,6 +60,9 @@ hat einen Speicherverbrauch von $\mathcal{O}(n)$. Durch einen
|
|||
\textbf{Akkumulator}\xindex{Akkumulator} kann dies verhindert werden:
|
||||
\inputminted[numbersep=5pt, tabsize=4]{haskell}{scripts/haskell/fakultaet-akkumulator.hs}
|
||||
|
||||
\subsection{Listen}
|
||||
\todo[inline]{Cons-Operator, Unendliche Listen}
|
||||
|
||||
\section{Beispiele}
|
||||
\subsection{Hello World}
|
||||
Speichere folgenden Quelltext als \texttt{hello-world.hs}:
|
||||
|
|
Binary file not shown.
|
@ -1,5 +1,98 @@
|
|||
\chapter{Programmiertechniken}
|
||||
\section{Rekursion}
|
||||
\todo[inline]{Tail-Recursion}
|
||||
\index{Rekursion|(}
|
||||
|
||||
\begin{definition}[rekursive Funktion]\xindex{Funktion!rekursive}
|
||||
Eine Funktion $f: X \rightarrow X$ heißt rekursiv definiert,
|
||||
wenn in der Definition der Funktion die Funktion selbst wieder
|
||||
steht.
|
||||
\end{definition}
|
||||
|
||||
\begin{beispiel}[rekursive Funktionen]
|
||||
\begin{bspenum}
|
||||
\item Fibonacci-Funktion:\xindex{Fibonacci-Funktion}
|
||||
\begin{align*}
|
||||
fib: \mdn_0 &\rightarrow \mdn_0\\
|
||||
fib(n) &= \begin{cases}
|
||||
n &\text{falls } n \leq 1\\
|
||||
fib(n-1) + fib(n-2) &\text{sonst}
|
||||
\end{cases}
|
||||
\end{align*}
|
||||
\item Fakultät:\xindex{Fakultät}
|
||||
\begin{align*}
|
||||
!: \mdn_0 &\rightarrow \mdn_0\\
|
||||
n! &= \begin{cases}
|
||||
1 &\text{falls } n \leq 1\\
|
||||
n\cdot (n-1)! &\text{sonst}
|
||||
\end{cases}
|
||||
\end{align*}
|
||||
\item \label{bsp:binomialkoeffizient} Binomialkoeffizient:\xindex{Binomialkoeffizient}
|
||||
\begin{align*}
|
||||
\binom{\cdot}{\cdot}: \mdn_0 \times \mdn_0 &\rightarrow \mdn_0\\
|
||||
\binom{n}{k} &= \begin{cases}
|
||||
1 &\text{falls } k=0 \lor k = n\\
|
||||
\binom{n-1}{k-1}+\binom{n-1}{k} &\text{sonst}
|
||||
\end{cases}
|
||||
\end{align*}
|
||||
\end{bspenum}
|
||||
\end{beispiel}
|
||||
|
||||
Ein Problem von rekursiven Funktionen in Computerprogrammen ist der
|
||||
Speicherbedarf. Für jeden rekursiven Aufruf müssen alle Umgebungsvariablen
|
||||
der aufrufenden Funktion (\enquote{stack frame}) gespeichert bleiben,
|
||||
bis der rekursive Aufruf beendet ist. Im Fall der Fibonacci-Funktion
|
||||
sieht ist der Call-Stack in \cref{fig:fib-callstack} abgebildet.
|
||||
|
||||
\begin{figure}[htp]
|
||||
\centering
|
||||
\includegraphics*[width=0.5\linewidth, keepaspectratio]{figures/fib-callstack.png}
|
||||
\caption{Call-Stack der Fibonacci-Funktion}
|
||||
\label{fig:fib-callstack}
|
||||
\end{figure}
|
||||
|
||||
\begin{bemerkung}
|
||||
Die Anzahl der rekursiven Aufrufe der Fibonacci-Funktion $f_C$ ist:
|
||||
\[f_C(n) = \begin{cases}
|
||||
1 &\text{falls } n=0\\
|
||||
2 \cdot fib(n) - 1 &\text{falls } n \geq 1
|
||||
\end{cases}\]
|
||||
\end{bemerkung}
|
||||
\begin{beweis}\leavevmode
|
||||
\begin{itemize}
|
||||
\item Offensichtlich gilt $f_C(0) = 1$
|
||||
\item Offensichtlich gilt $f_C(1) = 1 = 2 \cdot fib(1) - 1$
|
||||
\item Offensichtlich gilt $f_C(2) = 3 = 2 \cdot fib(2) - 1$
|
||||
\item Für $n \geq 3$:
|
||||
\begin{align*}
|
||||
f_C(n) &= 1 + f_C(n-1) + f_C(n-2)\\
|
||||
&= 1 + (2\cdot fib(n-1)-1) + (2 \cdot fib(n-2)-1)\\
|
||||
&=2\cdot (fib(n-1) + fib(n-2)) - 1\\
|
||||
&=2 \cdot fib(n) - 1
|
||||
\end{align*}
|
||||
\end{itemize}
|
||||
\end{beweis}
|
||||
|
||||
Mit Hilfe der Formel von Moivre-Binet folgt:
|
||||
|
||||
\[f_C \in \mathcal{O} \left (\frac{\varphi^n- \psi^n}{\varphi - \psi} \right) \text{ mit } \varphi := \frac{1+ \sqrt{5}}{2} \text{ und }\psi := 1 - \varphi\]
|
||||
|
||||
Dabei ist der Speicherbedarf $\mathcal{O}(n)$. Dieser kann durch
|
||||
das Benutzen eines Akkumulators signifikant reduziert werden.\todo{TODO}
|
||||
|
||||
\begin{definition}[linear rekursive Funktion]\xindex{Funktion!linear rekursive}
|
||||
Eine Funktion heißt linear rekursiv, wenn in jedem Definitionszweig
|
||||
der Funktion höchstens ein rekursiver Aufruf vorkommt.
|
||||
\end{definition}
|
||||
|
||||
\begin{definition}[endrekursive Funktion]\xindex{Funktion!endrekursive}\xindex{tail recursive}
|
||||
Eine Funktion heißt endrekursiv, wenn in jedem Definitionszweig
|
||||
der Rekursive aufruf am Ende des Ausdrucks steht. Der rekursive
|
||||
Aufruf darf also insbesondere nicht in einen anderen Ausdruck
|
||||
eingebettet sein.
|
||||
\end{definition}
|
||||
|
||||
\todo[inline]{Beispiele für linear rekusrive, endrekursive Funktionen (alle Kombinationen+gegenbeispiele}
|
||||
|
||||
\index{Rekursion|(}
|
||||
\section{Backtracking}
|
||||
|
||||
|
|
|
@ -24,7 +24,8 @@ TODO
|
|||
\section*{Erforderliche Vorkenntnisse}
|
||||
Grundlegende Kenntnisse vom Programmieren, insbesondere mit Java,
|
||||
wie sie am KIT in \enquote{Programmieren} vermittelt werden, werden
|
||||
vorausgesetzt.
|
||||
vorausgesetzt. Außerdem könnte ein grundlegendes Verständnis für
|
||||
das O-Kalkül aus \enquote{Grundbegriffe der Informatik} hilfreich sein.
|
||||
|
||||
Die Unifikation wird wohl auch in \enquote{Formale Systeme}
|
||||
erklärt; das könnte also hier von Vorteil sein.
|
||||
|
|
BIN
documents/Programmierparadigmen/figures/fib-callstack.png
Normal file
BIN
documents/Programmierparadigmen/figures/fib-callstack.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
|
@ -0,0 +1,14 @@
|
|||
fib(3)
|
||||
├ call(fib(2))
|
||||
│ ├─ call(fib(1))
|
||||
│ │ └─ return 1
|
||||
│ ├─ call(fib(0))
|
||||
│ │ └─ return 1
|
||||
│ └ return fib(1)+fib(0)=1+1
|
||||
├ call(fib(1))
|
||||
│ ├─ call(fib(1))
|
||||
│ │ └─ return 1
|
||||
│ ├─ call(fib(0))
|
||||
│ │ └─ return 1
|
||||
│ └ return fib(1)+fib(0)=1+1
|
||||
└ return fib(2)+fib(1)=2+2
|
Loading…
Add table
Add a link
Reference in a new issue