diff --git a/Semester_2/Einheit_03/Grundlagen-Algorithmen.ipynb b/Semester_2/Einheit_03/Grundlagen-Algorithmen.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..37b2b2c33f667eef38bb6429586ef28b0dfff4ee
--- /dev/null
+++ b/Semester_2/Einheit_03/Grundlagen-Algorithmen.ipynb
@@ -0,0 +1,1381 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "e7ac2738-e0bb-4c7f-a03f-10fa7ec5b71e",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "# <font color='blue'>**Nichtlineare Datenstrukturen**</font>\n",
+    "\n",
+    "## **<font color='blue'>Komplexität</font>** \n",
+    "\n",
+    "Ein wichtiges Maß, um Algorithmen zu bewerten und zu vergleichen, ist die **Komplexität**.\n",
+    "**Komplexität** beschreibt den maximalen Ressourcenbedarf in Abhängigkeit der Problemgröße \n",
+    "dargestellt durch die Zahl $n$. \n",
+    "In der Regel sind dies die Speicherkomplexität $S(n)$, d.h. der maximal benötigte Speicherplatz\n",
+    "bei einem Problem der Größe $n$, oder die Zeitkomplexität $T(n)$, d.h. die Zahl an Operationen bei einem Problem \n",
+    "der Größe $n$, die je nach Taktrate proportional zu CPU-Zeit ist. \n",
+    "\n",
+    "Z.B. ist die Zeitkomplexität bei einem Skalarprodukt $s$ zweier Vektoren $x$ und $y$ \n",
+    "mit $n$ Komponenten bezüglich der Multiplikations- und Additionsoperationen: \n",
+    "\n",
+    "\\begin{equation}\n",
+    " s \\;=\\; x_1 y_1 + \\; ... \\;+ x_n y_n \n",
+    "\\quad\n",
+    "\\rightarrow\n",
+    "\\quad\n",
+    "T_{mult}(n) = n \\; , \\quad\n",
+    "T_{add}(n) = n-1\\; , \\quad\n",
+    "T_{arith}(n) = 2n-1\\; ,\n",
+    "\\end{equation}\n",
+    "\n",
+    "was durch einfaches Abzählen der Operationen nachzuvollziehen ist. \n",
+    "Eine vollständige Komplexitätsbeschreibung erfolgt über die drei Fälle:\n",
+    "\n",
+    "* **best case** (der günstigste Fall) <br>\n",
+    "      Der günstigste Fall ereignet sich bei bestimmten Eingabegrößen, \n",
+    "      für die der Algorithmus minimalen Speicherplatz bzw. minimale Laufzeit benötigt.\n",
+    "* **average case** (der Normalfall bzw. Durchschnittsfall) <br>\n",
+    "      Die average-case-Komplexität ist das gemäß einer Wahrscheinlichkeitsverteilung \n",
+    "      für alle Eingaben gewichtete Mittel der Laufzeit bzw. des Speicherplatzbedarfs.\n",
+    "* **worst case** (der schlechteste Fall) <br>\n",
+    "      Der schlechteste Fall ereignet sich bei bestimmten Eingabegrößen, \n",
+    "      für die der Algorithmus maximalen Speicherplatz bzw. maximale Laufzeit benötigt. \n",
+    "      \n",
+    "### **<font color='blue'>Landau-Notation</font>**\n",
+    "\n",
+    "Entscheidende Aussage der Komplexität ist, wie sich der zu leistende Aufwand für große Probleme darstellt. \n",
+    "Daher wird zur Bestimmung eine Abschätzung für **große** $n$ vorgenommen. \n",
+    "Als Nomenklatur wird das Landau-Symbol $O(f(n))$ herangezogen, dessen mathematische Definition \n",
+    "\n",
+    "\\begin{equation}\n",
+    "O(f(n)) \\;=\\; \\{\\; g: \\mathbb{N} \\rightarrow \\mathbb{N}\n",
+    "            \\mid \\; \\exists n_0 > 0 \\wedge \\exists \\; c > 0\n",
+    "            \\text{, so dass} \\; \\forall \\; n > n_0 : \\; g(n) \\leq c f(n) \\;\\}, \n",
+    "\\end{equation}\n",
+    "\n",
+    "ist: $O(f(n))$ ist die Menge aller der Funktionen $g(n)$, für die es zwei Konstanten $n_0$ und $c$ gibt, so dass für alle $n > n_0$ gilt: $g(n) \\leq c \\cdot f(n)$.\n",
+    "Wäre nun $g(n)$ die exakte Komplexität, besagt die Definition, dass die $O$-Notation eine **obere Schranke** angibt, welche selbst im ungünstigsten Fall nicht überschritten wird. \n",
+    "$g(n)=O(f(n))$ bedeutet also, dass $g(n)$ ab einer gewissen Anzahl von Eingabewerten ($n>n_0$) stets kleiner als $c f(n)$ ist. <br>\n",
+    "Kurz gesagt bedeutet $g(n)=O(f(n))$, dass für große $n$ die Funktion $f(n)$ eine obere Schranke darstellt. <br>\n",
+    "$O(f(n))$ kann man also auch aus einer Grenzwertbetrachtung für große Zahlen $n$ herleiten oder z.B. über vollständige Induktion.\n",
+    "\n",
+    "### **<font color='blue'>Komplexitätsklassen</font>**\n",
+    "\n",
+    "Übliche Schranken $f(n)$ für die Komplexität sind Potenzen von $n^k$, \n",
+    "($n, n^2, n^3, ... $), $\\log(n)$ oder $a^n$, wobei $a$ eine Konstante $a>1$\n",
+    "oder sogar selbst $n$ sein kann. Die folgende Tabelle\n",
+    "\n",
+    "md\"\n",
+    "$$\n",
+    "\\begin{aligned}\n",
+    "& \\text {Tabelle: Zeitkomplexitäten}\\\\\n",
+    "&\\begin{array}{rcccccc}\n",
+    "      n & \\log(n) &  n   &  n \\log(n) & n^2     & \\; 2^n   & \\; n^n \\\\ \n",
+    "      \\hline\n",
+    "     10 & 1       & 10^1 &  \\; 10     & 10^2\\;  & 10^3\\;   &   10^{10}\\;  \\\\\n",
+    "    100 & 2       & 10^2 & 2\\; 10^2   & 10^4\\;  & 10^{30}  &   10^{200} \\\\\n",
+    "  1.000 & 3       & 10^3 & 3\\; 10^3   & 10^6\\;  & (\\infty) & (\\infty)\\\\\n",
+    " 10.000 & 4       & 10^4 & 4\\; 10^4   & 10^8\\;  & (\\infty) & (\\infty) \\\\\n",
+    "100.000 & 5       & 10^5 & 5\\; 10^5   & 10^{10} & (\\infty) & (\\infty) \\\\\n",
+    "\\hline\n",
+    "\\end{array}\n",
+    "\\end{aligned}\n",
+    "$$\n",
+    "\"\n",
+    "\n",
+    "zeigt, das die Komplexität $\\log(n)$ günstiger ist als die mit $n^k$ ist und die Formen $a^n$ bereits für kleine Werte $n$ sehr große Werte annehmen. \n",
+    "Diese großen Werte sind \\textit{fast unendlich} $(\\infty)$, wenn man sich vor Augen führt, dass eine Stunde $3.6\\; 10^9 \\mu s$, ein Tag $8.64\\; 10^{10} \\mu s$ und ein Jahr $3.15\\; 10^{13} \\mu s$ sind und man bei derzeitiger Hardware grob von 1 Operation in einer $\\mu s$ (Mikro-Sekunde) ausgehen kann.\n",
+    "\n",
+    "\n",
+    "<img src=\"Pics/Komplexitaetsklassen.png\"  width=\"45%\" height=\"45%\">\n",
+    "\n",
+    "* Die **logarithmische Komplexität** $O(log(n))$ ist außerordentlich günstig, \n",
+    "ebenso wie lineare $O(n)$ und überlineare $O(n\\;log(n))$.\n",
+    "\n",
+    "* Algorithmen mit einer Komplexität der Form $O(n^k)$ mit $ k>1$ \n",
+    "werden als polynomiale Algorithmen bezeichnet. \n",
+    "Sie gelten als **ausführbar** und **effizient**.\n",
+    "\n",
+    "* Demgegenüber stehen die Algorithmen mit einer \n",
+    "exponentiellen Komplexität der Form $O(a^n)$. \n",
+    "Sie gelten als **nicht ausführbar**. \n",
+    "\n",
+    "* **Nicht-deterministisch polynomiale** Probleme lassen \n",
+    "sich unter Umständen mit polynomialer Komplexität lösen \n",
+    "und haben die Eigenschaft, dass für Fragestellungen, \n",
+    "zu denen kein durchführbarer Algorithmus bekannt ist, \n",
+    "zumindest eine gefundenen Lösung in polynomialer Laufzeit \n",
+    "verifiziert werden kann. \n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d024bdde-545c-4c2a-916f-ab80e3717c1e",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "## **<font color='blue'>Sortieren</font>** \n",
+    "\n",
+    "Sinn: Zugriff auf sortierte Daten wesentlich effizienter \n",
+    "\n",
+    "Ein grundlegendes Beispiel für Algorithmen ist das Sortieren von Elementen \n",
+    "\n",
+    "\\begin{equation}\n",
+    "    a[0], a[1], ... , a[n-1]\n",
+    "\\end{equation}\n",
+    "\n",
+    "entsprechend einer **Ordnungsfunktion** $f()$, die auf $a[i]$ angewendet wird.\n",
+    "\n",
+    "Gesucht ist die **Permutation** $i_0, i_1, ... , i_{n-1}$, so dass \n",
+    "\n",
+    "\\begin{equation}\n",
+    "     f(a[i_0]) \\leq f(a[i_1]) \\leq ... \\leq f(a[i_{n-1}])\n",
+    "\\end{equation}\n",
+    "\n",
+    "gilt, in anderen Worten: die Reihenfolge, bei der die Ordnungsrelation für aufeinanderfolgende Elemente zutrifft. \n",
+    "\n",
+    "Bei den folgenden Verfahren wird davon ausgegangen, dass die zu sortierenden Elemente - einfache Zahlen - in einem Array $a$ vorliegen, das einen direkten, wahlfreien Zugriff ermöglicht. \n",
+    "\n",
+    "Unterschiede der Sortieralgorithmen ergeben sich z.B. aus der **Struktur der sortierenden Daten**, des **sequentiellen oder wahlfreien Zugriffs** oder auch bei den **Komplexitäten**.\n",
+    "\n",
+    "Grob lassen sich die Verfahren nach **direkten Verfahren**, bei denen $T_{Cm} = O(n^2)$ und/oder $T_{Mv} = O(n^2)$ sind, und **höheren Verfahren**, die oft günstiger bei der Komplexität aber in der Implementierung aufwändiger sind, klassifizieren.\n",
+    "\n",
+    "\n",
+    "### **<font color='blue'>Direkte Sortierverfahren</font>** \n",
+    "\n",
+    "Direkte Verfahren zeichnen sich dabei dadurch aus, dass sie in der Regel das gesamte Array behandeln, d.h. ein Problem der Größe $n$.\n",
+    "\n",
+    "#### **<font color='blue'>Direktes Einfügen</font>** \n",
+    "\n",
+    "Das direkte Einfügen entnimmt im $i$-ten Schritt aus der nicht sortierten Teilfolge $a[i], a[i+1], ... , a[n-1]$ das erste Element $a[i]$ und sortiert dies in die bereits sortiert vorliegende Sequenz $a[0], a[1], ... , a[i-1]$ ein. Hierzu wird zunächst die Einfügeposition $j+1$ linear von hinten beginnend gesucht, und die Einfügelücke geöffnet, indem die Elemente $a[j+1], a[j+2], ... , a[i-1]$ um eine Stelle nach hinten geschoben werden. Das ursprüngliche Element $a[i]$ wird dann auf die Position $a[j+1]$ gesetzt. \n",
+    "\n",
+    "Im Folgenden werden die Belegungen des Arrays $a$ nach den einzelnen Einfügeschritten \n",
+    "dargestellt. Die bereits sortierten Folgen sind unterstrichen, das einzusortierende \n",
+    "Element ist fett gesetzt.\n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{matrix} \n",
+    "[\\; \\underline{13},\\; \\mathbf{57},\\; 18,\\; 8,\\; 6,\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{13,\\; 57},\\; \\mathbf{18},\\; 8,\\; 6,\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{13,\\; 18,\\; 57},\\; \\mathbf{8},\\; 6,\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{8,\\; 13,\\; 18,\\; 57},\\; \\mathbf{6},\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 13,\\; 18,\\; 57},\\; \\mathbf{61},\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 13,\\; 18,\\; 57,\\; 61},\\; \\mathbf{97},\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 13,\\; 18,\\; 57,\\; 61,\\; 97},\\; \\mathbf{12} \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13,\\; 18,\\; 57,\\; 61,\\; 97} \\;] \n",
+    "\\end{matrix} \n",
+    "\\end{equation}\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "042b203d-e2e1-484f-92de-a77f8b9ac8e2",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 [13] [57] [18, 8, 6, 61, 97, 12]\n",
+      "2 [13, 57] [18] [8, 6, 61, 97, 12]\n",
+      "3 [13, 18, 57] [8] [6, 61, 97, 12]\n",
+      "4 [8, 13, 18, 57] [6] [61, 97, 12]\n",
+      "5 [6, 8, 13, 18, 57] [61] [97, 12]\n",
+      "6 [6, 8, 13, 18, 57, 61] [97] [12]\n",
+      "7 [6, 8, 13, 18, 57, 61, 97] [12] []\n",
+      "* [6, 8, 12, 13, 18, 57, 61, 97]\n"
+     ]
+    }
+   ],
+   "source": [
+    "def sort_insertion( a ): \n",
+    "    for i in range( 1, len( a ) ):\n",
+    "        print( i, a[:i], a[i:i+1], a[i+1:] ) \n",
+    "        a_i = a[i]   # Aktuelles Element\n",
+    "        j = i-1\n",
+    "        while ( j >= 0 and a_i < a[j] ): # Vergleich und \n",
+    "            a[j+1] = a[j]               # Verschieben nach rechts bzw. öffnen der Lücke \n",
+    "            j -= 1\n",
+    "        a[j+1] = a_i  # Aktuelles Element einfügen\n",
+    "    print( '*', a ) \n",
+    "\n",
+    "sort_insertion( [ 13, 57, 18, 8, 6, 61, 97, 12 ] ) "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "46d46a7a-da33-47e2-8e82-346ad9ac87f7",
+   "metadata": {},
+   "source": [
+    "#### **<font color='blue'>Binäres Einfügen</font>** \n",
+    "\n",
+    "Das Verfahren läßt sich beschleunigen, indem \n",
+    "die bereits erfolgte Sortierung der Teilsequenz \n",
+    "$a[0], a[1], ... , a[i-1]$ ausgenutzt wird. \n",
+    "\n",
+    "Im Folgenden ist die binäre Suche der Einfügeposition \n",
+    "der Zahl 12 unter Angabe der Indizes \\texttt{j}, \n",
+    "\\texttt{ug} und \\texttt{og} illustriert: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "% use packages: array\n",
+    "\\begin{array}[c]{lcl}\n",
+    "\\texttt{j} & \\texttt{ug:og} &  \\\\ \n",
+    "           & \\texttt{0:6} & [\\;\\underline{6,\\; 8,\\; 13,\\; 18,\\; 57,\\; 61,\\; 97}, 12 \\;]\\\\ \n",
+    "\\texttt{3} & \\texttt{0:2} & [\\;\\underline{6,\\; 8,\\; 13},\\; \\mathbf{18},\\; 57,\\; 61,\\; 97, 12 \\;] \\\\ \n",
+    "\\texttt{1} & \\texttt{2:2} & [\\; 6,\\; \\mathbf{8},\\; \\underline{13},\\; 18,\\; 57,\\; 61,\\; 97, 12 \\;] \\\\ \n",
+    "\\texttt{2} & \\texttt{2:1} & [\\; 6,\\; 8,\\; \\underline{\\mathbf{13}},\\; 18,\\; 57,\\; 61,\\; 97, 12 \\;]\n",
+    "\\end{array}\n",
+    "\\end{equation}\n",
+    "\n",
+    "Die folgende Implementierung ersetzt die Rekursion der binären Suche durch \n",
+    "eine Iteration."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "60d9adf9-fac5-4631-8974-11783e334469",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "1 [13] [57] [18, 8, 6, 61, 97, 12]\n",
+      "2 [13, 57] [18] [8, 6, 61, 97, 12]\n",
+      "3 [13, 18, 57] [8] [6, 61, 97, 12]\n",
+      "4 [8, 13, 18, 57] [6] [61, 97, 12]\n",
+      "5 [6, 8, 13, 18, 57] [61] [97, 12]\n",
+      "6 [6, 8, 13, 18, 57, 61] [97] [12]\n",
+      "7 [6, 8, 13, 18, 57, 61, 97] [12] []\n",
+      "* [6, 8, 12, 13, 18, 57, 61, 97]\n"
+     ]
+    }
+   ],
+   "source": [
+    "def sort_binary_insertion( a ):\n",
+    "    for i in range( 1, len( a ) ):\n",
+    "        print( i, a[:i], a[i:i+1], a[i+1:] ) \n",
+    "        a_i = a[i]   # Aktuelles Element\n",
+    "        # binäre Suche der Einfügestelle über eine Iteration \n",
+    "        ug = 0; og = i-1\n",
+    "        while( ug <= og ):\n",
+    "            j = ( ug + og ) // 2 \n",
+    "            if ( a_i < a[j] ): og = j-1\n",
+    "            else:              ug = j+1\n",
+    "        # Verschieben nach rechts bzw. öffnen der Lücke \n",
+    "        a[ug+1:i+1] = a[ug:i]\n",
+    "        #for j in range( i, ug, -1 ):\n",
+    "        #    a[j] = a[j-1];\n",
+    "        a[ug] = a_i  # Aktuelles Element einfügen\n",
+    "    print( '*', a ) \n",
+    "\n",
+    "sort_binary_insertion( [ 13, 57, 18, 8, 6, 61, 97, 12 ] ) "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "95324903-ea1d-4767-9b2d-d5af5e601773",
+   "metadata": {},
+   "source": [
+    "Komplexitäten für die Vergleichoperationen $T_{Cm}$: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "T _{Cm}^{Mn} \\;=\\; T _{Cm}^{Mx} \\;=\\; T _{Cm}^{Av} \\;=\\; \n",
+    "\\sum_{i=2}^{n} \\log_2 i \\;\\approx \\;\\int_2^n \\log_2 i \\; \\text{d} i \n",
+    "\\;\\approx\\; O(n \\log(n))\n",
+    "\\end{equation}\n",
+    "\n",
+    "Die Komplexität $ T_{Mv}$ wird gegenüber dem direkten Einfügen nicht beeinflußt. \n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c5b61d12-04bd-440e-ae21-04fe7b1b519b",
+   "metadata": {},
+   "source": [
+    "#### **<font color='blue'>Direktes Auswählen</font>** \n",
+    "\n",
+    "Die Zahl der Zuweisungen läßt sich beim Sortierverfahren **Direktes Auswählen** reduzieren, \n",
+    "in dem man das kleinste Element der unsortierten Sequenz $a[i], a[i+1], ... , a[n-1]$ sucht, \n",
+    "und dieses durch Austausch an die erste Stelle der unsortierten Sequenz setzt, indem man es mit $a[i]$ austauscht. \n",
+    "Dadurch ist die sortierte Sequenz $a[0], a[1], ... , a[i-1]$ um ein Element verlängert worden. \n",
+    "Im nächsten Schritt wird somit eine verkürzte Sequenz durchsucht. \n",
+    "\n",
+    "Im Beispiel ist das kleinste Element in der Sequenz $a[i], a[i+1], ... , a[n-1]$\n",
+    "fett gesetzt, die sortierte Sequenz wieder unterstrichen: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{matrix} \n",
+    "[\\; 13,\\; 57,\\; 18,\\; 8,\\; \\mathbf{6},\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{6},\\; 57,\\; 18,\\; \\mathbf{8},\\; 13,\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8},\\; 18,\\; 57,\\; 13,\\; 61,\\; 97,\\; \\mathbf{12} \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12},\\; 57,\\; \\mathbf{13},\\; 61,\\; 97,\\; 18 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13},\\; 57,\\; 61,\\; 97,\\; \\mathbf{18} \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13,\\; 18},\\; 61,\\; 97,\\; \\mathbf{57} \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13,\\; 18,\\; 57},\\; 97,\\; \\mathbf{61} \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13,\\; 18,\\; 57,\\; 61},\\; 97 \\;] \\\\\n",
+    "\\end{matrix}\n",
+    "\\end{equation}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "c8a0f512-6413-4650-acbf-4e7848d4b92d",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0 [] [13, 57, 18, 8, 6, 61, 97, 12]\n",
+      "1 [6] [57, 18, 8, 13, 61, 97, 12]\n",
+      "2 [6, 8] [18, 57, 13, 61, 97, 12]\n",
+      "3 [6, 8, 12] [57, 13, 61, 97, 18]\n",
+      "4 [6, 8, 12, 13] [57, 61, 97, 18]\n",
+      "5 [6, 8, 12, 13, 18] [61, 97, 57]\n",
+      "6 [6, 8, 12, 13, 18, 57] [97, 61]\n",
+      "7 [6, 8, 12, 13, 18, 57, 61] [97]\n",
+      "* [6, 8, 12, 13, 18, 57, 61, 97]\n"
+     ]
+    }
+   ],
+   "source": [
+    "def sort_selection( a ):\n",
+    "    for i in range( 0, len( a ) ):\n",
+    "        print( i, a[:i], a[i:] ) \n",
+    "        i_min = i\n",
+    "        for j in range( i+1, len( a ) ):   # Kleinsten Wert suchen\n",
+    "            if( a[j] < a[i_min] ): i_min = j;  \n",
+    "        a[i], a[i_min] = a[i_min], a[i]  # Austauschen \n",
+    "    print( '*', a ) \n",
+    "\n",
+    "sort_selection( [ 13, 57, 18, 8, 6, 61, 97, 12 ] ) "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "6a94e6bf-576a-4677-8f63-e830339b42fe",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "Für die Komplexitäten der Zuweisungen (Index $Mv$) \n",
+    "\n",
+    "\\begin{equation}\n",
+    "T _{Mv}^{Mn} \\,=\\, 3n -3 \\,=\\, O(n) \\, , \n",
+    "\\quad \n",
+    "T _{Mv}^{Mx} \\,=\\, \\frac 1 2 ( n^2 + 3n - 4 ) \\,=\\, O(n^2) \\; , \n",
+    "\\quad \n",
+    "T _{Mv}^{Av} \\,=\\, O(n \\log(n))\n",
+    "\\end{equation}\n",
+    "\n",
+    "Die Komplexität der Vergleiche ist immer die selbe und entspricht dem Maximalfall des direkten Einfügens: \n",
+    "    \n",
+    "\\begin{equation}\n",
+    "T _{Cm}^{Mn} \\;=\\; T _{Cm}^{Mx} \\;=\\; T _{Cm}^{Av} \\;=\\; \n",
+    "\\frac 1 2 (n^2-n)\\;=\\; O(n^2)\n",
+    "\\end{equation}\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "fca70245-7782-4989-969a-2a337c25cee7",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "#### **<font color='blue'>Direktes Austauschen / Bubble-Sort</font>** \n",
+    "\n",
+    "Beginnend mit dem letzten aktuellen Elementpaar $a[n-2]$ und $a[n-1]$ werden Vergleiche entsprechend der Ordnungsrelation durchgeführt \n",
+    "(Anmerkung: die Indices bei 'C++' laufen von $0$ bis $n-1$). \n",
+    "Falls $a[n-1] < a[n-2]$ wird mit den Elementen ein Austausch (swap) durchgeführt. \n",
+    "Im nächsten Teilschritt werden nun die aktuellen benachbarten Elemente $a[n-3]$ und $a[n-2]$ behandelt. \n",
+    "Im weiteren Verlauf wandert die kleinste Zahl nach vorn und darüberhinaus werden die anderen Zahlen in der Sequenz implizit \n",
+    "**vorsortiert**. Mit diesem Vorgehen *von hinten nach vorne* ergibt sich die Sequenz:\n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{matrix} \n",
+    "[\\; 13,\\; 57,\\; 18,\\; 8,\\; \\mathbf{6},\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; \\underline{6},\\; 13,\\; 57,\\; 18\\;, \\mathbf{8},\\; 12,\\; 61,\\; 97 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8},\\; 13,\\; 57,\\; 18,\\; \\mathbf{12},\\; 61,\\; 97 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12},\\; \\mathbf{13},\\; 57,\\; 18,\\; 61,\\; 97 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13},\\; \\mathbf{18},\\; 57,\\; 61,\\; 97 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13,\\; 18},\\; \\mathbf{57},\\; 61,\\; 97 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13,\\; 18,\\; 57},\\; \\mathbf{61},\\; 97 \\;] \\\\\n",
+    "[\\; \\underline{6,\\; 8,\\; 12,\\; 13,\\; 18,\\; 57,\\; 61},\\; \\mathbf{97} \\;] \\\\\n",
+    "\\end{matrix}\n",
+    "\\end{equation}\n",
+    "\n",
+    "Im drittletzten Schritt erfolgt hier kein swappen mehr. \n",
+    "Dies liegt an der *Vorsortierung*, so dass der Algorithmus abgebrochen werden kann, wenn kein Austausch mehr erfolgt ist. \n",
+    "Der zugehörie Code ist dann z.B.: \n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "5009c3e7-aaef-45d5-886d-1e73f118cb52",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0 [] [13, 57, 18, 8, 6, 61, 97, 12]\n",
+      "1 [6] [13, 57, 18, 8, 12, 61, 97]\n",
+      "2 [6, 8] [13, 57, 18, 12, 61, 97]\n",
+      "3 [6, 8, 12] [13, 57, 18, 61, 97]\n",
+      "4 [6, 8, 12, 13] [18, 57, 61, 97]\n",
+      "* [6, 8, 12, 13, 18, 57, 61, 97]\n"
+     ]
+    }
+   ],
+   "source": [
+    "import numpy as np\n",
+    "def sort_bubble( a ):\n",
+    "    for i in range( 0, len( a ) ):\n",
+    "        print( i, a[:i], a[i:] ) \n",
+    "        swapped = False\n",
+    "        for j in range( len( a )-1, i, -1 ):\n",
+    "            if a[j-1] > a[j]:\n",
+    "                a[j-1], a[j] = a[j], a[j-1]  # Austauschen\n",
+    "                swapped = True \n",
+    "        if not swapped:\n",
+    "            break\n",
+    "    print( '*', a ) \n",
+    "\n",
+    "sort_bubble( [ 13, 57, 18, 8, 6, 61, 97, 12 ] ) \n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "6067d7f5-632e-4751-82cb-4e222c1817b7",
+   "metadata": {},
+   "source": [
+    "Die Komplexitäten sind  \n",
+    "\n",
+    "\\begin{equation}\n",
+    "T _{Cm}^{Mn} \\,=\\, O(n)\\, , \n",
+    "\\quad \n",
+    "T _{Cm}^{Mx} \\,=\\, T _{Cm}^{Av} \\,=\\, O(n^2) \\; ,\n",
+    "\\end{equation}\n",
+    "\n",
+    "und \n",
+    "\n",
+    "\\begin{equation}\n",
+    "T _{Mv}^{Mn} \\,=\\, 0 \\, , \n",
+    "\\quad \n",
+    "T _{Mv}^{Mx} \\,=\\, \\frac 3 2 ( n^2 - n ) \\,=\\, O(n^2) \\; , \n",
+    "\\quad \n",
+    "T _{Mv}^{Av} \\,=\\, \\frac 3 4 ( n^2 - n ) \\,=\\, O(n^2) \\; ,\n",
+    "\\end{equation}\n",
+    "trotzdem nicht besser als beim direkten Einfügen. \n",
+    "Ein Vorteil des Verfahrens liegt sicherlich in der \n",
+    "einfachen Implementierung. \n",
+    "\n",
+    "#### **<font color='blue'>Laufzeitvergleich der Direkten Verfahren </font>** \n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "id": "bcab2496-baa7-44f5-8069-559828bb20d9",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Einfügen          3.863898992538452\n",
+      "Binäres Einfügen  0.14241480827331543\n",
+      "Auswählen         4.684155702590942\n",
+      "Bubble            9.374122381210327\n"
+     ]
+    }
+   ],
+   "source": [
+    "import numpy as np \n",
+    "import time \n",
+    "\n",
+    "def sort_insertion( a ): \n",
+    "    for i in range( 1, len( a ) ):\n",
+    "        a_i = a[i]   # Aktuelles Element\n",
+    "        j = i-1\n",
+    "        while ( j >= 0 and a_i < a[j] ): # Vergleich und \n",
+    "            a[j+1] = a[j]                # Verschieben nach rechts bzw. öffnen der Lücke \n",
+    "            j -= 1\n",
+    "        a[j+1] = a_i  # Aktuelles Element einfügen\n",
+    "        \n",
+    "def sort_binary_insertion( a ):\n",
+    "    for i in range( 1, len( a ) ):\n",
+    "        a_i = a[i]\n",
+    "        ug = 0; og = i-1\n",
+    "        while( ug <= og ):\n",
+    "            j = ( ug + og ) // 2 \n",
+    "            if ( a_i < a[j] ): og = j-1\n",
+    "            else:              ug = j+1\n",
+    "        #for j in range( i, ug, -1 ):\n",
+    "        #    a[j] = a[j-1];\n",
+    "        a[ug+1:i+1] = a[ug:i]\n",
+    "        a[ug] = a_i  \n",
+    "        \n",
+    "def sort_selection( a ):\n",
+    "    for i in range( 0, len( a ) ):\n",
+    "        i_min = i\n",
+    "        for j in range( i+1, len( a ) ):   # Kleinsten Wert suchen\n",
+    "            if( a[j] < a[i_min] ): i_min = j;  \n",
+    "        a[i], a[i_min] = a[i_min], a[i]  # Austauschen \n",
+    "\n",
+    "def sort_bubble( a ):\n",
+    "    for i in range( 0, len( a ) ):\n",
+    "        swapped = False\n",
+    "        for j in range( len( a )-1, i, -1 ):\n",
+    "            if a[j-1] > a[j]:\n",
+    "                a[j-1], a[j] = a[j], a[j-1]  # Austauschen\n",
+    "                swapped = True \n",
+    "        if not swapped:\n",
+    "            break\n",
+    "\n",
+    "# Vektor der Werte\n",
+    "values = np.random.rand(1000)\n",
+    "repeat = 100 \n",
+    "\n",
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    vals = values.copy()\n",
+    "    sort_insertion( vals )\n",
+    "time_insertion = time.time()-start_time\n",
+    "\n",
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    vals = values.copy()\n",
+    "    sort_binary_insertion( vals )\n",
+    "time_binary_insertion = time.time()-start_time\n",
+    "\n",
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    vals = values.copy()\n",
+    "    sort_selection( vals )\n",
+    "time_selection = time.time()-start_time\n",
+    "\n",
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    vals = values.copy()\n",
+    "    sort_bubble( vals )\n",
+    "time_bubble = time.time()-start_time\n",
+    "\n",
+    "\n",
+    "print( \"Einfügen         \", time_insertion ) \n",
+    "print( \"Binäres Einfügen \", time_binary_insertion ) \n",
+    "print( \"Auswählen        \", time_selection ) \n",
+    "print( \"Bubble           \", time_bubble ) \n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "628beafc-34ee-4681-aac9-a6c8ab417244",
+   "metadata": {},
+   "source": [
+    "\n",
+    "### **<font color='blue'>Höhere Sortierverfahren</font>** \n",
+    "\n",
+    "Direkte Verfahren zeichnen sich dabei dadurch aus, dass sie in der Regel das gesamte Array behandeln, d.h. ein Problem der Größe $n$.\n",
+    "\n",
+    "#### **<font color='blue'>Divide-and Conquer Methodik</font>** \n",
+    "\n",
+    "Divide-and-Conquer bzw. teile-und-herrsche Verfahren stellen eine allgemeine Lösungsstrategie dar. \n",
+    "Das Vorgehen erfolgt in den drei Schritten: \n",
+    "\n",
+    "* **Zerlege** das Problem in **Teilprobleme**\n",
+    "* Finde die **Lösungen** der **Teilprobleme**\n",
+    "* Setze die Gesamtlösung als **Kombination der Lösungen** zusammen \n",
+    "\n",
+    "Das Vorgehen erfolgt **rekursiv**, d.h. die Lösung der Teilprobleme \n",
+    "wird wiederum mit diesen drei Schritten ermittelt, es sei denn \n",
+    "das resultierende Teilproblem ist trivial und seine Lösung \n",
+    "unmittelbar bekannt, so dass die Rekursion stoppt. \n",
+    "\n",
+    "Die resultierende Komplexität läßt sich allgemein angeben. <br>\n",
+    "Teilt man das Problem der Größe $n$ \n",
+    "in $a$ Teilprobleme der Größe $n/b$, so ist \n",
+    "die Komplexität berechenbar aus:\n",
+    "\n",
+    "\\begin{equation}\n",
+    "  T(n) = a \\cdot T(n/b) + t(n) \\; .\n",
+    "\\end{equation}\n",
+    "\n",
+    "Darin ist $t(n)$ der Aufwand für die Zerlegungs- und \n",
+    "Zusammensetzungsschritte. Geht man von einer \n",
+    "Gesamtproblemgröße $n = b^k$ aus, und ist $T(1) = c$ \n",
+    "der Aufwand für das triviale Problem, so ergeben sich die \n",
+    "Lösungen für die Gesamtkomplexität: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{split}\n",
+    "a<b : &\\quad T(n) \\leq c \\;\\frac{b}{b-a} n = O(n) \\\\\n",
+    "a=b : &\\quad T(n) = c \\; n \\;\\log_b n + 1 = O(n \\log n) \\\\\n",
+    "a>b : &\\quad T(n) \\leq c \\; \\frac{a}{a-b} \\; n^{\\log_b a} = O(n^{\\log_b a})\n",
+    "\\end{split}\n",
+    "\\end{equation}\n",
+    "\n",
+    "Oftmals ist $a=b=2$, so dass man auf die überlineare Komplexität \n",
+    "$O(n \\log n)$ stößt. <br>\n",
+    "Beispiele hierfür sind das **binäre Suchen**, \n",
+    "**Merge-Sort** und **Quick-Sort**."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "2a29019c-547c-47c5-b313-98f1787ee694",
+   "metadata": {},
+   "source": [
+    "#### **<font color='blue'>Merge-Sort</font>** \n",
+    "\n",
+    "Beim Merge-Sort wird die zu sortierende Sequenz ohne echten Aufwand rekursiv solange halbiert, \n",
+    "bis nur noch Sequenzen (Teilprobleme) der Größe 1 vorliegen. \n",
+    "Diese sind für sich alleine betrachtet **sortiert**, so dass zu deren Problemlösung nichts gemacht werden muss. \n",
+    "Für das Beispiel sieht die Aufspaltung so aus: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{matrix} \n",
+    "[\\; 13,\\; 57,\\; 18,\\; 8,\\; 6,\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; 13,\\; 57,\\; 18,\\; 8\\;], \\;[\\; 6,\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; 13,\\; 57\\;], \\;[\\; 18,\\; 8\\;], \\;[\\; 6,\\; 61\\;], \\;[\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\; 13\\;], \\;[\\; 57\\;], \\;[\\; 18\\;], \\;[\\; 8\\;], \\;[\\; 6\\;], \\;[\\; 61\\;], \\;[\\; 97\\;], \\;[\\; 12 \\;] \\;. \\\\\n",
+    "\\end{matrix}\n",
+    "\\end{equation}\n",
+    "\n",
+    "Die rekursive Funktion besitzt hier als Parameter \n",
+    "das Array `a` sowie den untersten Index `i_left`, ab dem sortiert werden soll, \n",
+    "und die Länge des Teilarrays `len_a`: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "id": "6d719409-8826-43fe-b197-e465d8695efb",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def merge_sort( a, i_left, len_a ):\n",
+    "    \n",
+    "    if len_a == 1: return \n",
+    "    \n",
+    "    len_a1 = len_a // 2\n",
+    "    len_a2 = len_a - len_a1 \n",
+    "    \n",
+    "    merge_sort( a, i_left, len_a1 )\n",
+    "    merge_sort( a, i_left+len_a1, len_a2 )\n",
+    "    \n",
+    "    merge_solutions( a, i_left, len_a1, len_a2 )"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f4f450bf-7b92-435d-af2d-3d7babfdf4a8",
+   "metadata": {},
+   "source": [
+    "Es muss aus den beiden sortiert vorliegenden Sequenzen \n",
+    "$a_1$ und $a_2$\n",
+    "eine gemeinsame, sortierte Sequenz $b$ entstehen. \n",
+    "Dies erfolgt nach dem Reisverschlussverfahren. \n",
+    "Hierbei wird der kleinste noch in den Teilsequenzen \n",
+    "$a_1$ und $a_2$ enthaltene Wert entnommen (und gestrichen) \n",
+    "und an die ursprünglich leere Sequenz $b$ angehängt. \n",
+    "Das Beispiel des letzten Merge-Schrittes ist: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{matrix} \n",
+    "a_1 = [\\; 8,\\; 13,\\; 18,\\; 57 \\;] \\quad\\searrow&\\\\\n",
+    "& b = [\\; 6,\\; 8,\\; 12,\\; 13,\\; 18,\\; 57,\\; 61,\\; 97 \\;] \\; . \\\\\n",
+    "a_2 = [\\; 6,\\; 12,\\; 61,\\; 97 \\;] \\quad\\nearrow&\\\\\n",
+    "\\end{matrix}\n",
+    "\\end{equation}\n",
+    "Die passende Funktion lautet:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "8fb821c6-f0b6-4b89-a5a7-ae58cdd5f7cf",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def merge_solutions( a, i_left, len_a1, len_a2 ):\n",
+    "    \n",
+    "    b = a[i_left:i_left+len_a1+len_a2].copy()     # Temporärer Array\n",
+    "    i_left1 = i_left\n",
+    "    i_left2 = i_left+len_a1\n",
+    "\n",
+    "    for k in range( len_a1+len_a2 ): \n",
+    "        # Nehme aus a1, wenn a2 leer oder Element von a1 <= a2\n",
+    "        if ( i_left2 >= i_left+len_a1+len_a2 ) or \\\n",
+    "           ( i_left1 < i_left+len_a1 and a[i_left1] <= a[i_left2]): \n",
+    "            b[k] = a[i_left1]\n",
+    "            i_left1 += 1  \n",
+    "        else:                     # sonst nehme aus a2\n",
+    "            b[k] = a[i_left2]\n",
+    "            i_left2 += 1\n",
+    "            \n",
+    "    # Zurückkopieren des gemischten Vektors \n",
+    "    #for k in range( len_a1+len_a2 ): a[i_left+k] = b[k]\n",
+    "    a[i_left:i_left+len_a1+len_a2] = b"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "22e687bf-94dc-43d9-aab6-ab853f01baf3",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "In der Implementierung wird für `b` ein temporärer Array erzeugt und dessen Inhalt abschließend wieder in den Teilbereich \n",
+    "des Arrays `a` zurückkopiert wird. Insgesamt liefern die Merge-Schritte ausgehend von den trivialen Problemen: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{matrix} \n",
+    "[\\; 13\\;], \\;[\\; 57\\;], \\;[\\; 18\\;], \\;[\\; 8\\;], \\;[\\; 6\\;], \\;[\\; 61\\;], \\;[\\; 97\\;], \\;[\\; 12 \\;] \\\\\n",
+    "[\\; 13,\\; 57\\;], \\;[\\; 8,\\; 18\\;], \\;[\\; 6,\\; 61\\;], \\;[\\; 12,\\; 97 \\;] \\\\\n",
+    "[\\; 8,\\; 13,\\; 18,\\; 57\\;], \\;[\\; 6,\\; 12,\\; 61,\\; 97 \\;] \\\\\n",
+    "[\\; 6,\\; 8,\\; 12,\\; 13,\\; 18,\\; 57,\\; 61,\\; 97 \\;] \\\\\n",
+    "\\end{matrix}\n",
+    "\\end{equation}\n",
+    "\n",
+    "Die Komplexitäten sind für den besten und schlechsten Fall gleich:\n",
+    "\n",
+    "\\begin{equation}\n",
+    "T _{Cm}^{Mn} \\,=\\, T _{Cm}^{Mx} \\,=\\, T _{Cm}^{Av} \\,=\\, O(n \\log n) \\; ,\n",
+    "\\quad \n",
+    "T _{Mv}^{Mn} \\,=\\, T _{Mv}^{Mx} \\,=\\, T _{Mv}^{Av} \\,=\\,O(n \\log n) \\; .\n",
+    "\\end{equation}\n",
+    "\n",
+    "Somit ist dieses Verfahren im Durchschnitt genauso gut oder \n",
+    "besser als die bisherigen. Nachteil ist jedoch die Notwendigkeit \n",
+    "eines temporären Arrays beim merge, der im letzen Schritt genauso \n",
+    "groß ist wie der zu sortierende. \n",
+    "\n",
+    "Unter Nutzung der **Python-Liste** mit ihren Methoden kann man auch folgenden Implementierung entwickeln:  "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "id": "958ed917-4e5d-4d17-8f71-afc7fa78e1ac",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def merge_sort_list( unsorted_list ):\n",
+    "    \n",
+    "    if len(unsorted_list) <= 1: return unsorted_list\n",
+    "\n",
+    "    i_middle = len(unsorted_list) // 2\n",
+    "    left_list  = unsorted_list[:i_middle]\n",
+    "    right_list = unsorted_list[i_middle:]\n",
+    "\n",
+    "    left_list  = merge_sort_list(left_list)\n",
+    "    right_list = merge_sort_list(right_list)\n",
+    "    \n",
+    "    return list( merge_lists(left_list, right_list) )\n",
+    "\n",
+    "def merge_lists( left_half, right_half ):\n",
+    "    res = []\n",
+    "    while len(left_half) != 0 and len(right_half) != 0:\n",
+    "        if left_half[0] < right_half[0]:\n",
+    "            res.append(left_half[0])\n",
+    "            left_half.remove(left_half[0])\n",
+    "        else:\n",
+    "            res.append(right_half[0])\n",
+    "            right_half.remove(right_half[0])\n",
+    "    if len(left_half) == 0:\n",
+    "        res = res + right_half\n",
+    "    else:\n",
+    "        res = res + left_half\n",
+    "    return res"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f367ed27-8a06-4268-90cc-6616e7ee2015",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "Der Laufzeitvergleich mit dem gleichen Vektor von oben liefert: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "id": "6424593e-628f-498d-9fcb-f3e362ee91b4",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Merge             0.3301358222961426\n",
+      "Merge with lists  0.15523695945739746\n"
+     ]
+    }
+   ],
+   "source": [
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    vals = values.copy()\n",
+    "    merge_sort( vals, 0, len(vals) )\n",
+    "time_merge = time.time()-start_time\n",
+    "\n",
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    vals = values.tolist()\n",
+    "    r_vals = merge_sort_list( vals )\n",
+    "time_merge_list = time.time()-start_time\n",
+    "\n",
+    "print( \"Merge            \", time_merge ) \n",
+    "print( \"Merge with lists \", time_merge_list ) "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "9151915b-41d1-4903-927d-a2b8adaec1f8",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "Folgend werden die Sortierverfahren des Numpy-Pakets genutzt, die natürlich schneller sind, das sie komplett in einer Compilersprache implementiert sind: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "id": "434b07c4-c846-472a-b077-c96d2f78958d",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Merge numpy       0.008358955383300781\n",
+      "Quick numpy       0.0012059211730957031\n",
+      "Heap  numpy       0.0019860267639160156\n"
+     ]
+    }
+   ],
+   "source": [
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    np.sort(values, kind='mergesort')\n",
+    "time_merge_numpy = time.time()-start_time\n",
+    "\n",
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    np.sort(values, kind='quicksort')\n",
+    "time_quick_numpy = time.time()-start_time\n",
+    "\n",
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    np.sort(values, kind='heapsort')\n",
+    "time_heap_numpy = time.time()-start_time\n",
+    "\n",
+    "print( \"Merge numpy      \", time_merge_numpy ) \n",
+    "print( \"Quick numpy      \", time_quick_numpy ) \n",
+    "print( \"Heap  numpy      \", time_heap_numpy ) \n",
+    " "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4aee6dcf-d797-45cf-98f5-94f3ef414132",
+   "metadata": {},
+   "source": [
+    "#### **<font color='blue'>Quick-Sort</font>** \n",
+    "\n",
+    "Während beim Merge-Sort der Aufwand innerhalb der Verschmelzung der Teillösungen \n",
+    "versteckt ist, ist er es beim Quick-Sort innerhalb der Partitionierungsphase. \n",
+    "Die Aufteilung wird so vorgenommen, dass die Elemente der \n",
+    "ersten Teilsequenz alle kleiner als die Elemente der zweiten sind. \n",
+    "Hierzu wird ein Zerlegungselement $a[k]$ (Pivotelement), \n",
+    "wobei $k$ beliebig sein kann, gewählt. \n",
+    "Elemente des vorderen und hinteren Teil des Array, die größer bzw. \n",
+    "kleiner als das Pivotelement sind werden paarweise ausgetauscht, \n",
+    "bis eine Folge entstanden ist, für die gilt: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{split}\n",
+    "   \\text{linker Teil:} &\\quad \\; i = 0, 1, ..., j, : \\quad a[i] \\leq a[k] \\\\\n",
+    "   \\text{rechter Teil:} &\\quad \\; i = n-1, n-2, ..., j+1  : \\quad a[i] \\geq a[k] \n",
+    "\\end{split}\n",
+    "\\end{equation}\n",
+    "\n",
+    "Welche Zerlegungstelle $j$ gefunden wird und wie lang die Teilsequenzen \n",
+    "sind, ist so zufällig wie die Wahl des Pivotelementes.\n",
+    "Für das Beispiel ergeben sich die Folgen, \n",
+    "in denen die zur Zerlegung vorgesehenen Sequenzen unterstrichen sind,\n",
+    "und das Zerlegungselement fett gesetzt ist. \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{matrix} \n",
+    "[\\; \\underline{13,\\; 57,\\; 18,\\; \\mathbf 8,\\; 6,\\; 61,\\; 97,\\; 12} \\;] \\\\\n",
+    "[\\; \\underline{\\mathbf 6,\\; 8},\\; 18,\\; 57,\\; 13,\\; 61,\\; 97,\\; 12 \\;] \\\\\n",
+    "[\\;  6,\\; 8,\\;   \\underline{18,\\; 57,\\; \\mathbf {13},\\; 61,\\; 97,\\; 12} \\;] \\\\\n",
+    "[\\;  6,\\; 8,\\;   \\underline{\\mathbf {12},\\; 13},\\;  57,\\; 61,\\; 97,\\; 18 \\;] \\\\\n",
+    "[\\;  6,\\; 8,\\;   12,\\; 13,\\; \\underline{ 57,\\; \\mathbf {61},\\; 97,\\; 18} \\;] \\\\\n",
+    "[\\;  6,\\; 8,\\;   12,\\; 13,\\; \\underline{ \\mathbf {57},\\; 18},\\; 97,\\; 61 \\;] \\\\\n",
+    "[\\;  6,\\; 8,\\;   12,\\; 13,\\; 18,\\; 57,\\; \\underline{\\mathbf {97},\\; 61} \\;] \\\\\n",
+    "[\\;  6,\\; 8,\\;   12,\\; 13,\\; 18,\\; 57,\\; 61,\\; 97 \\;] \\\\\n",
+    "\\end{matrix}\n",
+    "\\end{equation}\n",
+    "\n",
+    "Die zugehörige Funktion lautet: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "id": "f2579fba-259d-4ed5-b29d-a83aa9b26ce9",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[6, 8, 12, 13, 18, 57, 61, 97]\n"
+     ]
+    }
+   ],
+   "source": [
+    "def quick_sort( a, ug, og ): \n",
+    "\n",
+    "    i, j = ug, og\n",
+    "    pivot = a[(ug+og)//2]  # Pivotelement\n",
+    "    while ( i <= j ): \n",
+    "        while ( a[i] < pivot ): i += 1\n",
+    "        while ( a[j] > pivot ): j -= 1\n",
+    "        if ( i <= j ):  \n",
+    "            a[i], a[j] = a[j], a[i]\n",
+    "            i += 1 ; j -= 1 \n",
+    "    #print( pivot, a ) \n",
+    "    # Teilen und Sortieren\n",
+    "    if ( ug < j ): quick_sort( a, ug, j )\n",
+    "    if ( i < og ): quick_sort( a, i, og )\n",
+    "\n",
+    "vals = [ 13, 57, 18, 8, 6, 61, 97, 12 ]\n",
+    "quick_sort( vals, 0, len(vals)-1 )\n",
+    "print( vals ) \n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "id": "c8bf3504-a04c-4578-9309-ca34fd28dc80",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "100 1000\n",
+      "Quick with array  0.14501237869262695\n",
+      "Quick with lists  0.07118535041809082\n"
+     ]
+    }
+   ],
+   "source": [
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    vals = values.copy()\n",
+    "    r_vals = quick_sort( vals, 0, len(vals)-1 )\n",
+    "time_quick_array = time.time()-start_time\n",
+    "\n",
+    "print( repeat, len(values) ) \n",
+    "start_time = time.time()\n",
+    "for i in range(repeat): \n",
+    "    vals = values.tolist()\n",
+    "    r_vals = quick_sort( vals, 0, len(vals)-1 )\n",
+    "time_quick_list = time.time()-start_time\n",
+    "\n",
+    "print( \"Quick with array \", time_quick_array ) \n",
+    "print( \"Quick with lists \", time_quick_list ) \n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "066c52c5-8d2f-4f54-92b1-ec24c110ea27",
+   "metadata": {},
+   "source": [
+    "Ein expliziter Zusammensetzungsschritt ist hier nicht notwendig, da implizit die Gesamtsortierung erreicht wird. \n",
+    "Die Komplexitäten sind je nachdem wie gut die Folgen vorsortiert sind: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "T _{Cm}^{Mn} \\,=\\, T _{Mv}^{Mn} \\,=\\, O(n) \\; ,\n",
+    "\\quad \n",
+    "T _{Cm}^{Av} \\,=\\, T _{Mv}^{Av} \\,=\\, O(n \\log n) \\; .\n",
+    "\\quad \n",
+    "T _{Cm}^{Mx} \\,=\\, T _{Mv}^{Mx} \\,=\\, O(n^2) \\; .\n",
+    "\\end{equation}\n",
+    "\n",
+    "Der Vorteil gegenüber Merge-Sort liegt darin, dass hier kein \n",
+    "zusätzlicher Speicherplatz benötigt wird, das Sortieren \n",
+    "erfolgt In-Place, auf dem Platz des gegebenen Arrays.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "84964082-54b0-4684-ac7f-f55fc4dc5dfe",
+   "metadata": {},
+   "source": [
+    "## **<font color='blue'>Entscheidungsprobleme</font>** \n",
+    "\n",
+    "Bei Entscheidungsproblemen gilt es, eine optimale Belegung eines Lösungsvektors im Hinblick auf eine zu minimierende oder zu maximierende Gütefunktion zu bestimmen.\n",
+    "Klassische Vertreter hierfür sind das Rucksack-Problem und das Wechselgeld-Problem.\n",
+    "\n",
+    "### **<font color='blue'>Rucksack-Problem</font>**\n",
+    "\n",
+    "Bei diesem Problem soll eine optimale Bepackung eines Rucksacks bestimmt werden. \n",
+    "Es stehen $n$ verschiedene Objekte zur Verfügung, jedes mit einem Gewicht $g_i$ und einem Nutzwert $w_i$. \n",
+    "Die Aufgabe besteht nun darin, die Objekte auszuwählen, die mit einem maximalen Gesamtgewicht $G$ in den Rucksack passen und den gesamten Nutzwert $W$ maximieren. \n",
+    "Welche Objekte ausgewählt werden, wird über eine Variable des Objekts $x_i$ gekennzeichnet, die den Wert 1 annimmt, falls das Objekt im Rucksack enthalten ist, sonst den Wert 0.  \n",
+    "Alle $ x_i $ zusammengefasst ergeben den Lösungsvektor $X$. \n",
+    "Knapp formuliert lautet das Problem also: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{split}\n",
+    "&\\text{Gegeben: } \\;n, w_i, g_i, G \\in \\mathbb{N} \\\\\n",
+    "&\\text{Bestimme: } \\; X = ( x_1, x_2, ... , x_n ) \n",
+    "\\quad \\text{mit} \\quad  x_i \\in [0,1] \\\\\n",
+    "&\\quad\\quad\\text{so dass}  \\quad \n",
+    "    W = \\sum_{i=1}^n x_i \\; w_i  \\rightarrow \\max \\; , \n",
+    "\\qquad \\text{wobei} \\quad\n",
+    "    G \\geq \\sum_{i=1}^n x_i \\; g_i \n",
+    "\\end{split}\n",
+    "\\end{equation}\n",
+    "\n",
+    "### **<font color='blue'>Wechselgeld-Problem</font>**\n",
+    "\n",
+    "Die Aufgabe beim Wechselgeld-Problem ist die Bestimmung der Münzen aus einem Vorrat von $n$ verschiedenen mit einem individuellen Wert $w_i$, \n",
+    "so dass die Wechselsumme $W$ genau getroffen wird und die Anzahl der gewählten Münzen minimal ist. \n",
+    "Der Lösungsvektor wird analog zum Rucksack-Problem aufgebaut, wobei die Münze $i$ dem Objekt $i$ gleichkommt.\n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{split}\n",
+    "&\\text{Gegeben: } \\;n, w_i, W \\in \\mathbb{N} \\\\\n",
+    "&\\text{Bestimme: } \\; X = ( x_1, x_2, ... , x_n ) \n",
+    "\\quad \\text{mit} \\quad  x_i \\in [0,1] \\\\\n",
+    "&\\quad\\quad\\text{so dass}  \\quad \n",
+    "    N = \\sum_{i=1}^n x_i   \\rightarrow \\min \\; , \n",
+    "\\quad \\text{wobei} \\quad\n",
+    "    W = \\sum_{i=1}^n x_i \\; w_i \n",
+    "\\end{split}\n",
+    "\\end{equation}\n",
+    "\n",
+    "### **<font color='blue'>Problem des Handlungsreisenden</font>**\n",
+    "\n",
+    "Das Problem des Handlungsreisenden - Traveling Salesman Problem (TSP) - versucht die kürzeste bzw. günstigste Rundreise durch einen Satz von $n$ Städten zu bestimmen. \n",
+    "Dabei darf in der Rundreise jede Stadt nur einmal besucht werden. \n",
+    "Die möglichen Verbindungen zwischen Städten sind in Form von Kanten gegeben, wobei die Städte den Knoten entsprechen. \n",
+    "Die Distanz zwischen zwei verbundenen Städten $i$ und $j$ ist durch die Kantenwichtung $B_{ij}$ gegeben \n",
+    "\n",
+    "Eine Lösung wird durch die Städtefolge bzw. Permutation $X = [x_1, x_2, ... , x_n]$ beschrieben. \n",
+    "Der Startpunkt kann zufällig gewählt werden, da es eine Rundreise ist.\n",
+    "Die Gesamtdistanz bzw. Kosten $C(X)$ für eine Lösung $X$ errechnen sich aus der Summe der Wichtungen der durchlaufenden Kanten: \n",
+    "\n",
+    "\\begin{eqnarray}\n",
+    "C(X) \\;=\\; \\sum_{i=1}^{n-1} B_{x_i x_{i+1}} + B_{x_n x_{1}}  \n",
+    "\\quad \\rightarrow \\quad \\min\n",
+    "\\end{eqnarray}\n",
+    "\n",
+    "Der letzte Summand berücksichtigt die Rückreise von der letzten zur ersten Stadt. \n",
+    "\n",
+    "\n",
+    "### **<font color='blue'>Brute-Force</font>**\n",
+    "\n",
+    "Brute-Force-Algorithmen zeichnen sich dadurch aus, dass sie keine besondere Strategie oder algorithmischen Feinheiten beinhalten. \n",
+    "Sie behandeln die Problemstellung sehr einfach, so dass auch eine Implementierung schnell und einfach erfolgen kann. \n",
+    "Ein Brute-Force-Algorithmus ist gleichbedeutend mit der Bewertung aller denkbaren Möglichkeiten. \n",
+    "Dies wird z.B. im Vergleich der linearen Suche mit der binären Suche bereits deutlich. \n",
+    "Zwar wird immer die korrekte Lösung gefunden, jedoch ist der Aufwand in der Ausführung relativ hoch. \n",
+    "Der Brute-Force-Algorithmus testet bei den beiden Problemstellungen alle Möglichkeiten \n",
+    "der Auswahl, prüft ob die Restriktionen eingehalten wird, und merkt sich für die zulässigen Möglichkeiten den Lösungsvektor, für den die Zielvorgabe optimiert. \n",
+    "\n",
+    "#### **<font color='blue'>Rucksackproblem</font>**\n",
+    "\n",
+    "Beim Rucksackproblem werden zur Auswertung der Gewichtrestriktion und des Nutzwerts je $n-1$ Additionen und $n$ Multiplikationen durchgeführt, \n",
+    "d.h. der Aufwand je Vektor $X$ ist in der Größenordnung $O(n)$. \n",
+    "Da es $2^n$ Kombinationsmöglichkeiten für die Belegung des Vektors $X$ gibt ist der notwendige Gesamtaufwand\n",
+    "\n",
+    "\\begin{equation}\n",
+    "T_{Mult+Add}(n)  \\,=\\,  O(n \\cdot 2^n) \\; .\n",
+    "\\end{equation}\n",
+    "\n",
+    "\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "id": "5e7335ad-62ba-49fc-b1a4-d1ba8b728ba9",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(55, (0, 1, 1, 0, 0, 1))\n"
+     ]
+    }
+   ],
+   "source": [
+    "import itertools\n",
+    "def rucksack_brute_force( weights, values, capacity ):\n",
+    "\n",
+    "    max_value = max_x = 0\n",
+    "    \n",
+    "    all_combinations = [[0,1] for i in range(len(weights))]\n",
+    "\n",
+    "    for x in itertools.product( *all_combinations ):\n",
+    "        \n",
+    "        value = weight = 0\n",
+    "        for i in range( len(x) ):\n",
+    "            value  += x[i] * values[i]\n",
+    "            weight += x[i] * weights[i]\n",
+    "\n",
+    "        if weight <= capacity and value > max_value:\n",
+    "            max_value = value\n",
+    "            max_x = x[:]\n",
+    "\n",
+    "    return max_value, max_x \n",
+    "\n",
+    "print( rucksack_brute_force([100, 50, 45, 20, 10, 5], [40, 35, 18, 4, 10, 2], 100 ) )\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "792550d7-682e-4a6f-85e5-1febc0bffc8c",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "#### **<font color='blue'>Wechselgeldproblem</font>**\n",
+    "\n",
+    "Hier gibt es eine analoges Vorgehen: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "id": "5f477150-5801-4cd8-84c6-304e87217cc3",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "(4, (0, 0, 0, 1, 1, 0, 1, 0, 0, 1))\n"
+     ]
+    }
+   ],
+   "source": [
+    "import math \n",
+    "\n",
+    "def wechselgeld_brute_force( values, target ):\n",
+    "\n",
+    "    min_number = math.inf\n",
+    "    min_x = ()\n",
+    "    \n",
+    "    all_combinations = [[0,1] for i in range(len(values))]\n",
+    "\n",
+    "    for x in itertools.product( *all_combinations ):\n",
+    "        \n",
+    "        value = number = 0\n",
+    "        for i in range( len(x) ):\n",
+    "            value  += x[i] * values[i]\n",
+    "            number += x[i]\n",
+    "\n",
+    "        if value == target and number < min_number:\n",
+    "            min_number = number\n",
+    "            min_x = x[:]\n",
+    "\n",
+    "    return min_number, min_x \n",
+    "\n",
+    "print( wechselgeld_brute_force( [1, 1, 1, 1, 1, 5, 5, 10, 10, 25], 32 ) )\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "389aca60-7c69-4418-9d4b-223815f66bd4",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "\n",
+    "#### **<font color='blue'>Problem des Handlungsreisenden</font>**\n",
+    "\n",
+    "Die Brute-Force-Komplexität umfaßt hier die Anzahl der möglichen Permutationen, die sich über die Fakulätsfunktion ergibt. \n",
+    "Diese liegt jenseits der $2^n$ Komplexität, so dass Brute-Force für größere Probleme nicht ausführbar ist."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b28ad86c-df91-4f8c-924b-99cdc7679ee2",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "### **<font color='blue'>Greedy-Algorithmen</font>**\n",
+    "\n",
+    "* Greedy-Algorithmen bauen den Lösungsvektor **stückweise** auf, indem z.B. zunächst eine Variable $x_i$ bestimmt und festgelegt wird, danach eine zweite $x_j$ usw., \n",
+    "um die Ziel- oder Gütefunktion zu maximieren bzw. zu minimieren. \n",
+    "* Bei jedem der Schritte wird die Entscheidung aber nur aufgrund der lokal bzw. **derzeit verfügbaren Information** getätigt.\n",
+    "* Stehen im Einzelschritt mehrere zulässige Teillösungen $x_k$ zur Verfügung, so wird die Teillösung gewählt, die die Gütefunktion am stärksten verbessert. \n",
+    "In anderen Worten: die aktuelle Entscheidung wird **gierig** (greedy) gewählt, so dass der Nutzen der Teillösung maximiert wird.\n",
+    "* Bei dieser Vorgehenweise werden also **keine Änderung** bereits getroffener Entscheidungen in Erwägung gezogen und es werden auch nicht die zukünftigen Entscheidungsmöglichkeiten in die Lösungsfindung einbezogen. \n",
+    "\n",
+    "Dieses Greedy-Prinzip kann in vielen Fällen funktionieren und tatsächlich auf eine optimale Lösung führen. \n",
+    "Oftmals ist die Lösung nicht optimal, aber meist auch nicht nicht ganz schlecht.\n",
+    "Die Lösungsqualität hängt sicher stark von der Entscheidungsstrategie ab, die im Einzelschritt angewendet wird. \n",
+    "\n",
+    "Der Vorteil der Greedy-Algorithmen ist in der einfachen Implementierung und in der extrem kurzen Laufzeit zu sehen.\n",
+    "Letztere hängt natürlich vom Aufwand der gewählten Entscheidungsstrategie ab. "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a1340d58-d4f2-45f7-94d5-3dc94295f6d1",
+   "metadata": {},
+   "source": [
+    "#### **<font color='blue'>Wechselgeld-Problem</font>**\n",
+    "\n",
+    "Als Entscheidungsstrategie wird im Beispiel folgende gewählt: \n",
+    "\n",
+    "Wähle die Münze, die der Differenz zwischen $W$ und dem \n",
+    "aktuellen Wert der bisher gewählten Münzen $\\sum_{i=1}^n x_i \\; w_i$ am nächsten \n",
+    "kommt, aber kleiner ist.\n",
+    "\n",
+    "Hat man beispielsweise fünf 1 Cent, zwei 5 Cent, zwei 10 Cent und eine 25 Cent Münze im Geldbeutel und muß in Summe 32 Cent herausgeben, so würde die Entscheidung auf die Wahl der 25 Cent Münze fallen.\n",
+    "25 Cent ist die größte Münze, die kleiner-gleich der 32 Cent ist. \n",
+    "Es fehlen noch 7 Cent. \n",
+    "Die zweite Wahl fällt somit auf die 5 Cent Münze.\n",
+    "Für die restlichen 2 Cent werden in den letzten beiden \n",
+    "Entscheidungen je 1 Cent Münzen gewählt: \n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{split}\n",
+    "w_i : &                    \\quad [\\;1,\\;1,\\;1,\\;1,\\;1,\\;5,\\;5,10,10,25\\;] \\\\\n",
+    "\\text{1. Entscheidung} \\; &\\quad [\\;0,\\;0,\\;0,\\;0,\\;0,\\;0,\\;0, \\;0, \\;\\;0,\\;\\; 1\\;] \\; \\rightarrow \\;\\; W_X = 25 \\\\\n",
+    "\\text{2. Entscheidung} \\; &\\quad [\\;0,\\;0,\\;0,\\;0,\\;0,\\;0,\\;1, \\;0, \\;\\;0,\\;\\; 1\\;] \\; \\rightarrow \\;\\; W_X = 30 \\\\\n",
+    "\\text{3. Entscheidung} \\; &\\quad [\\;0,\\;0,\\;0,\\;0,\\;1,\\;0,\\;1, \\;0, \\;\\;0,\\;\\; 1\\;] \\; \\rightarrow \\;\\; W_X = 31 \\\\\n",
+    "\\text{4. Entscheidung} \\; &\\quad [\\;0,\\;0,\\;0,\\;1,\\;1,\\;0,\\;1, \\;0, \\;\\;0,\\;\\; 1\\;] \\; \\rightarrow \\;\\; W_X = 32\n",
+    "\\end{split}\n",
+    "\\end{equation}\n",
+    "\n",
+    "\n",
+    "#### **<font color='blue'>Rucksack-Problem</font>**\n",
+    "\n",
+    "Hier wird wiederholt ein noch nicht eingepackter Gegenstand nach einem Kriterium ausgewählt und in den Rucksack gepackt, sofern die Gewichtsrestriktion nicht überschritten wird.\n",
+    "Verschiedene Kriterien sind denkbar: \n",
+    "\n",
+    "* **Wert**: der Gegenstand mit höchstem Nutzwert wird ewählt. \n",
+    "* **Gewicht**: der Gegenstand mit geringstem Gewicht wird ewählt. \n",
+    "* **Dichte**: der Gegenstand mit bestem Nutzwert-Gewichts-Verhältnis (Dichte) wird gewählt.\n",
+    "\n",
+    "Ein Beispiel soll nun zeigen, dass für die verschiedenen Kriterien auch verschiedene Lösungen entstehen. \n",
+    "In der folgenden Tabelle sind die Objektgewichte $g_i$ und -werte $w_i$ aufgelistet. Als Gewichtsrestriktion \n",
+    "wird $G=100$ gewählt. \n",
+    "\n",
+    "\n",
+    "\\begin{equation}\n",
+    "\\begin{matrix}\n",
+    "i \\;& g_i & w_i & w_i/g_i & \\textrm{Kriterium:} & \\textrm{Wert} & \\textrm{Gewicht} & \\textrm{Dichte} & \\textrm{Optimum} \\\\ \n",
+    "1 \\;& 100 & 40 & 0,4 && 1 & 0 & 0 & 0 \\\\ \n",
+    "2 \\;& 50 & 35 & 0,7 && 0 & 0 & 1 & 1 \\\\ \n",
+    "3 \\;& 45 & 18 & 0,4 && 0 & 1 & 0 & 1 \\\\ \n",
+    "4 \\;& 20 & 4 & 0,2 && 0 & 1 & 1 & 0 \\\\ \n",
+    "5 \\;& 10 & 10 & 1,0 && 0 & 1 & 1 & 0 \\\\ \n",
+    "6 \\;& 5 & 2 & 0,4 && 0 & 1 & 1 & 1 \\\\ \n",
+    "  &   &   && \\sum_{i=1}^n x_i g_i :  & 100 & 80 & 85 & 100 \\\\ \n",
+    "  &   &   && \\sum_{i=1}^n x_i w_i :  & 40 & 34 & 51 & 55 \\\\\n",
+    "\\end{matrix}\n",
+    "\\end{equation}\n",
+    "\n",
+    "Beim Wert-Kriterium wird als erstes das teuerste Objekt gewählt, also $i=1$, das mit $w_1=40$ am wertvollsten ist. \n",
+    "Danach ist der Rucksack voll und es kann nichts mehr eingepackt werden. \n",
+    "Das resultierende Gewicht von 100 liegt am geforderten Limit von 100, als Gesamtwert wird 40 erreicht. \n",
+    "\n",
+    "Das Gewichts-Kriterium berücksichtigt an keiner Stelle die Objektwerte. \n",
+    "Nacheinander werden die Objekte 6, 5, 4 und 3 gewählt. \n",
+    "Gewicht 2 passt danach nicht mehr Rucksack. \n",
+    "Der zulässige Gesamtmasse wird nicht erreicht, der Gesamtwert ist mit 34 schlechter als beim Wert-Kriterium. \n",
+    "\n",
+    "Das beste Ergebnis der drei Kriterien liefert das Dichte-Kriterium mit einem Gesamtwert von 51 und einem Gesamtgewicht von 85. \n",
+    "\n",
+    "Keines der Kriterien liefert jedoch die optimale Lösung. \n",
+    "Diese ist in der letzten Spalte angegeben und führt auf einen Gesamtwert von 55 und ein Gesamtgewicht von 100. \n",
+    "Um diese Lösung zu finden, kann man neben der Brute-Force-Methode auch die der Dynamischen Programmierung verwenden."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d573b1a1-cce0-4406-9430-ef99e57762aa",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "@deathbeds/ipydrawio": {
+   "xml": ""
+  },
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.10"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/Semester_2/Einheit_03/Pics/Greedy.svg b/Semester_2/Einheit_03/Pics/Greedy.svg
new file mode 100644
index 0000000000000000000000000000000000000000..381e4158797d10c5d8abddac0f3f612c295c8fd2
--- /dev/null
+++ b/Semester_2/Einheit_03/Pics/Greedy.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="windows-1252" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="430px" preserveAspectRatio="none" style="width:332px;height:430px;background:#FFFFFF;" version="1.1" viewBox="0 0 332 430" width="332px" zoomAndPan="magnify"><defs/><g><!--class Auftrag--><g id="elem_Auftrag"><rect codeLine="1" fill="#F1F1F1" height="129.4844" id="Auftrag" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="136" x="98" y="294"/><ellipse cx="135.5" cy="310" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M137.8438,305.6719 C136.9063,305.2344 136.3125,305.0938 135.4375,305.0938 C132.8125,305.0938 130.8125,307.1719 130.8125,309.8906 L130.8125,311.0156 C130.8125,313.5938 132.9219,315.4844 135.8125,315.4844 C137.0313,315.4844 138.1875,315.1875 138.9375,314.6406 C139.5156,314.2344 139.8438,313.7813 139.8438,313.3906 C139.8438,312.9375 139.4531,312.5469 138.9844,312.5469 C138.7656,312.5469 138.5625,312.625 138.375,312.8125 C137.9219,313.2969 137.9219,313.2969 137.7344,313.3906 C137.3125,313.6563 136.625,313.7813 135.8594,313.7813 C133.8125,313.7813 132.5156,312.6875 132.5156,310.9844 L132.5156,309.8906 C132.5156,308.1094 133.7656,306.7969 135.5,306.7969 C136.0781,306.7969 136.6875,306.9531 137.1563,307.2031 C137.6406,307.4844 137.8125,307.7031 137.9063,308.1094 C137.9688,308.5156 138,308.6406 138.1406,308.7656 C138.2813,308.9063 138.5156,309.0156 138.7344,309.0156 C139,309.0156 139.2656,308.875 139.4375,308.6563 C139.5469,308.5 139.5781,308.3125 139.5781,307.8906 L139.5781,306.4688 C139.5781,306.0313 139.5625,305.9063 139.4688,305.75 C139.3125,305.4844 139.0313,305.3438 138.7344,305.3438 C138.4375,305.3438 138.2344,305.4375 138.0156,305.75 L137.8438,305.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="54" x="154.5" y="314.8467">Auftrag</text><line style="stroke:#181818;stroke-width:0.5;" x1="99" x2="233" y1="326" y2="326"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="95" x="104" y="342.9951">name : string</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="112" x="104" y="359.292">dauer : int/float</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="105" x="104" y="375.5889">wert : int/float</text><line style="stroke:#181818;stroke-width:0.5;" x1="99" x2="233" y1="382.8906" y2="382.8906"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="124" x="104" y="399.8857">__repr__() : string</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="62" x="104" y="416.1826">__init__()</text></g><!--class Maschinenbelegungsplan--><g id="elem_Maschinenbelegungsplan"><rect codeLine="2" fill="#F1F1F1" height="227.2656" id="Maschinenbelegungsplan" rx="2.5" ry="2.5" style="stroke:#181818;stroke-width:0.5;" width="318" x="7" y="7"/><ellipse cx="71.75" cy="23" fill="#ADD1B2" rx="11" ry="11" style="stroke:#181818;stroke-width:1.0;"/><path d="M74.0938,18.6719 C73.1563,18.2344 72.5625,18.0938 71.6875,18.0938 C69.0625,18.0938 67.0625,20.1719 67.0625,22.8906 L67.0625,24.0156 C67.0625,26.5938 69.1719,28.4844 72.0625,28.4844 C73.2813,28.4844 74.4375,28.1875 75.1875,27.6406 C75.7656,27.2344 76.0938,26.7813 76.0938,26.3906 C76.0938,25.9375 75.7031,25.5469 75.2344,25.5469 C75.0156,25.5469 74.8125,25.625 74.625,25.8125 C74.1719,26.2969 74.1719,26.2969 73.9844,26.3906 C73.5625,26.6563 72.875,26.7813 72.1094,26.7813 C70.0625,26.7813 68.7656,25.6875 68.7656,23.9844 L68.7656,22.8906 C68.7656,21.1094 70.0156,19.7969 71.75,19.7969 C72.3281,19.7969 72.9375,19.9531 73.4063,20.2031 C73.8906,20.4844 74.0625,20.7031 74.1563,21.1094 C74.2188,21.5156 74.25,21.6406 74.3906,21.7656 C74.5313,21.9063 74.7656,22.0156 74.9844,22.0156 C75.25,22.0156 75.5156,21.875 75.6875,21.6563 C75.7969,21.5 75.8281,21.3125 75.8281,20.8906 L75.8281,19.4688 C75.8281,19.0313 75.8125,18.9063 75.7188,18.75 C75.5625,18.4844 75.2813,18.3438 74.9844,18.3438 C74.6875,18.3438 74.4844,18.4375 74.2656,18.75 L74.0938,18.6719 Z " fill="#000000"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="180" x="92.25" y="27.8467">Maschinenbelegungsplan</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="324" y1="39" y2="39"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="241" x="13" y="55.9951">geplante_auftraege : list[Auftrag]</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="176" x="13" y="72.292">planungsdauer : int/float</text><line style="stroke:#181818;stroke-width:0.5;" x1="8" x2="324" y1="79.5938" y2="79.5938"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="201" x="13" y="96.5889">get_gesamtwert() : int/float</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="208" x="13" y="112.8857">get_gesamtdauer() : int/float</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="115" x="13" y="129.1826">zuruecksetzen()</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="152" x="13" y="145.4795">hinzufuegen(Auftrag)</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="202" x="13" y="161.7764">greedy_planen(list[Auftrag])</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="220" x="13" y="178.0732">_waehle(list[Auftrag]) : Auftrag</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="306" x="13" y="194.3701">_filter_auftrage(list[Auftrag]) : list[Auftrag]</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="124" x="13" y="210.667">__repr__() : string</text><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="62" x="13" y="226.9639">__init__()</text></g><!--reverse link Maschinenbelegungsplan to Auftrag--><g id="link_Maschinenbelegungsplan_Auftrag"><path codeLine="4" d="M166,247.774 C166,263.77 166,279.562 166,293.967 " fill="none" id="Maschinenbelegungsplan-backto-Auftrag" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="166,234.316,162,240.316,166,246.316,170,240.316,166,234.316" style="stroke:#181818;stroke-width:1.0;"/></g><!--SRC=[bL9BRiCW4Drp2Y-TIb7ttVK0FK5LeQdpJ539D1e6HVNf2vPJvsEiT0NpFlDXw0B5sBocNeMSwSReZMAtzmp-H81BxE8n41kpZ3TFs-rVWghefN4e5uMbKGk730OVzNqoVzIzvIZXZX8anvxrkG_Vf6lbr3f4EkW9ektclwwnrAEs8Kb2znMX0xZTr8KP75AVyl3SJcElg9q0knzRego_UgiLbpqHzW4t-aoSbrHtzZuePDgGMqZnuBwi5Hp5sl7zeehdjQhMizSYDcPAdL6c0sRpZDz_WPahcwvGInrTikSMVW40]--></g></svg>
\ No newline at end of file
diff --git a/Semester_2/Einheit_03/Pics/Greedy_algo.svg b/Semester_2/Einheit_03/Pics/Greedy_algo.svg
new file mode 100644
index 0000000000000000000000000000000000000000..81bc4689c7815d39788f13169bd012d6a2c34287
--- /dev/null
+++ b/Semester_2/Einheit_03/Pics/Greedy_algo.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="windows-1252" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="484px" preserveAspectRatio="none" style="width:519px;height:484px;background:#FFFFFF;" version="1.1" viewBox="0 0 519 484" width="519px" zoomAndPan="magnify"><defs/><g><ellipse cx="334" cy="16" fill="#222222" rx="10" ry="10" style="stroke:none;stroke-width:1.0;"/><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="167" x="250.5" y="67"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="147" x="260.5" y="88.1387">erhaltene Liste kopieren</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="109" x="279.5" y="142"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="89" x="289.5" y="163.1387">Aufträge filtern</text><g id="elem_#7"><polygon fill="#F1F1F1" points="302,217,314,229,302,241,290,229,302,217" style="stroke:#181818;stroke-width:0.5;"/></g><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="155" x="102.5" y="295"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="135" x="112.5" y="316.1387">besten Auftrag wählen</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="324" x="7" y="370"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="304" x="17" y="391.1387">gewählten Auftrag geplanten Aufträgen hinzufügen</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="413" x="100.5" y="445"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="393" x="110.5" y="466.1387">gewählten Auftrag aus Liste der zu planenden Aufträge entfernen</text><ellipse cx="302" cy="312" fill="none" rx="10" ry="10" style="stroke:#222222;stroke-width:1.0;"/><ellipse cx="302.5" cy="312.5" fill="#222222" rx="6" ry="6" style="stroke:none;stroke-width:1.0;"/><!--link start to erhaltene Liste kopieren--><g id="link_start_erhaltene Liste kopieren"><path d="M334,26.177 C334,35.269 334,49.527 334,61.485 " fill="none" id="start-to-erhaltene Liste kopieren" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="334,66.791,338,57.791,334,61.791,330,57.791,334,66.791" style="stroke:#181818;stroke-width:1.0;"/></g><!--link erhaltene Liste kopieren to Auftr?ge filtern--><g id="link_erhaltene Liste kopieren_Aufträge filtern"><path d="M334,101.201 C334,111.692 334,125.463 334,136.818 " fill="none" id="erhaltene Liste kopieren-to-Aufträge filtern" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="334,141.844,338,132.844,334,136.844,330,132.844,334,141.844" style="stroke:#181818;stroke-width:1.0;"/></g><!--link Auftr?ge filtern to #7--><g id="link_Aufträge filtern_#7"><path d="M326.416,176.115 C320.711,188.24 313.009,204.607 307.792,215.692 " fill="none" id="Aufträge filtern-to-#7" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="305.586,220.379,313.0369,213.9381,307.7146,215.8547,305.798,210.5324,305.586,220.379" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="183" x="321.9289" y="216.1456">passender auftrag verbleibend?</text></g><!--link #7 to besten Auftrag w?hlen--><g id="link_#7_besten Auftrag wählen"><path d="M295.091,234.587 C278.823,245.388 237.335,272.933 208.885,291.822 " fill="none" id="#7-to-besten Auftrag wählen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="204.436,294.776,214.1464,293.1304,208.6015,292.0104,209.7215,286.4655,204.436,294.776" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="10" x="253" y="272.2104">ja</text></g><!--link besten Auftrag w?hlen to gew?hlten Auftrag geplanten Auftr?gen hinzuf?gen--><g id="link_besten Auftrag wählen_gewählten Auftrag geplanten Aufträgen hinzufügen"><path d="M177.559,329.201 C175.978,339.692 173.903,353.463 172.192,364.818 " fill="none" id="besten Auftrag wählen-to-gewählten Auftrag geplanten Aufträgen hinzufügen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="171.434,369.844,176.7315,361.5412,172.1797,364.8999,168.821,360.3481,171.434,369.844" style="stroke:#181818;stroke-width:1.0;"/></g><!--link gew?hlten Auftrag geplanten Auftr?gen hinzuf?gen to gew?hlten Auftrag aus Liste der zu planenden Auftr?ge entfernen--><g id="link_gewählten Auftrag geplanten Aufträgen hinzufügen_gewählten Auftrag aus Liste der zu planenden Aufträge entfernen"><path d="M199.285,404.0202 C220.617,415.3049 249.25,430.4512 271.633,442.2912 " fill="none" id="gewählten Auftrag geplanten Aufträgen hinzufügen-to-gewählten Auftrag aus Liste der zu planenden Aufträge entfernen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="276.309,444.7649,270.2247,437.0201,271.8895,442.4265,266.4832,444.0913,276.309,444.7649" style="stroke:#181818;stroke-width:1.0;"/></g><!--link gew?hlten Auftrag aus Liste der zu planenden Auftr?ge entfernen to Auftr?ge filtern--><g id="link_gewählten Auftrag aus Liste der zu planenden Aufträge entfernen_Aufträge filtern"><path d="M328.737,444.9808 C344.111,431.6532 362,411.1674 362,388 C362,228 362,228 362,228 C362,211.171 354.577,193.645 347.375,180.601 " fill="none" id="gewählten Auftrag aus Liste der zu planenden Aufträge entfernen-to-Aufträge filtern" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="344.745,176.007,345.746,185.8049,347.2295,180.346,352.6884,181.8296,344.745,176.007" style="stroke:#181818;stroke-width:1.0;"/></g><!--link #7 to end--><g id="link_#7_end"><path d="M302,241.263 C302,255.665 302,280.629 302,296.455 " fill="none" id="#7-to-end" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="302,301.836,306,292.836,302,296.836,298,292.836,302,301.836" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="25" x="303" y="272.2104">nein</text></g><!--SRC=[TOzB3e9044JtdgB32acuWeQzDo0iXbZpqKbBvgC9v-4OxhYOCq0C2rrsLVNhhh8wrlK9JWiRmA2ByG5qVmm63dn8NXDbSFEaGDAaZ5j48waOXFVWAno9716Add2zXUcJUYuew1NGtaH7FHANgTcIhtdIDitPLrYclQqmMC5V9LzdqeR7AEUtMh4_raJqMu7yrHWfK_ABEmw1Wqmj_fM3zSWEjGp37PNLyGC0]--></g></svg>
\ No newline at end of file
diff --git a/Semester_2/Einheit_03/Pics/Greedy_filter.svg b/Semester_2/Einheit_03/Pics/Greedy_filter.svg
new file mode 100644
index 0000000000000000000000000000000000000000..3ee26d6638f8477e1025bbf52fcfa167bc1889dd
--- /dev/null
+++ b/Semester_2/Einheit_03/Pics/Greedy_filter.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="windows-1252" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="432px" preserveAspectRatio="none" style="width:620px;height:432px;background:#FFFFFF;" version="1.1" viewBox="0 0 620 432" width="620px" zoomAndPan="magnify"><defs/><g><ellipse cx="321.2658" cy="16" fill="#222222" rx="10" ry="10" style="stroke:none;stroke-width:1.0;"/><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="236" x="203.2658" y="67"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="216" x="213.2658" y="88.1387">verbleibende Planungszeit ermitteln</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="134" x="254.2658" y="142"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="114" x="264.2658" y="163.1387">neue Liste anlegen</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="152" x="245.2658" y="217"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="132" x="255.2658" y="238.1387">erhaltene Liste prüfen</text><g id="elem_#9"><polygon fill="#F1F1F1" points="429.2658,222,441.2658,234,429.2658,246,417.2658,234,429.2658,222" style="stroke:#181818;stroke-width:0.5;"/></g><g id="elem_#12"><polygon fill="#F1F1F1" points="356.2658,310,368.2658,322,356.2658,334,344.2658,322,356.2658,310" style="stroke:#181818;stroke-width:0.5;"/></g><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="238" x="199.2658" y="393"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="218" x="209.2658" y="414.1387">Auftrag der neuen Liste hinzufuegen</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="165" x="388.7658" y="305"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="145" x="398.7658" y="326.1387">neue Liste zurückgeben</text><ellipse cx="471.2658" cy="410" fill="none" rx="10" ry="10" style="stroke:#222222;stroke-width:1.0;"/><ellipse cx="471.7658" cy="410.5" fill="#222222" rx="6" ry="6" style="stroke:none;stroke-width:1.0;"/><!--link start to verbleibende Planungszeit ermitteln--><g id="link_start_verbleibende Planungszeit ermitteln"><path d="M321.2658,26.177 C321.2658,35.269 321.2658,49.527 321.2658,61.485 " fill="none" id="start-to-verbleibende Planungszeit ermitteln" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="321.2658,66.791,325.2658,57.791,321.2658,61.791,317.2658,57.791,321.2658,66.791" style="stroke:#181818;stroke-width:1.0;"/></g><!--link verbleibende Planungszeit ermitteln to neue Liste anlegen--><g id="link_verbleibende Planungszeit ermitteln_neue Liste anlegen"><path d="M321.2658,101.201 C321.2658,111.692 321.2658,125.463 321.2658,136.818 " fill="none" id="verbleibende Planungszeit ermitteln-to-neue Liste anlegen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="321.2658,141.844,325.2658,132.844,321.2658,136.844,317.2658,132.844,321.2658,141.844" style="stroke:#181818;stroke-width:1.0;"/></g><!--link neue Liste anlegen to erhaltene Liste pr?fen--><g id="link_neue Liste anlegen_erhaltene Liste prüfen"><path d="M321.2658,176.201 C321.2658,186.692 321.2658,200.463 321.2658,211.818 " fill="none" id="neue Liste anlegen-to-erhaltene Liste prüfen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="321.2658,216.844,325.2658,207.844,321.2658,211.844,317.2658,207.844,321.2658,216.844" style="stroke:#181818;stroke-width:1.0;"/></g><!--link erhaltene Liste pr?fen to #9--><g id="link_erhaltene Liste prüfen_#9"><path d="M397.6248,234 C402.3448,234 407.0648,234 411.7838,234 " fill="none" id="erhaltene Liste prüfen-to-#9" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="416.9058,234,407.9058,230,411.9058,234,407.9058,238,416.9058,234" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="164" x="449.1143" y="229.6215">weiterer Auftrag vorhanden?</text></g><!--link #9 to #12--><g id="link_#9_#12"><path d="M424.0158,241.185 C411.5988,255.813 380.3208,292.66 364.9988,310.712 " fill="none" id="#9-to-#12" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="361.4678,314.871,370.3418,310.5987,364.7037,311.0593,364.2431,305.4213,361.4678,314.871" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="10" x="398.2658" y="282.2104">ja</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="330" x="6" y="311.0531">Auftrag ist kurz genug für die verbleibende Planungszeit?</text></g><!--link #12 to Auftrag der neuen Liste hinzufuegen--><g id="link_#12_Auftrag der neuen Liste hinzufuegen"><path d="M352.8928,330.6319 C347.2808,343.3324 335.8338,369.2408 327.6358,387.7926 " fill="none" id="#12-to-Auftrag der neuen Liste hinzufuegen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="325.4178,392.813,332.7136,386.197,327.4383,388.2394,325.3959,382.9642,325.4178,392.813" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="10" x="341.2658" y="370.2104">ja</text></g><!--link Auftrag der neuen Liste hinzufuegen to erhaltene Liste pr?fen--><g id="link_Auftrag der neuen Liste hinzufuegen_erhaltene Liste prüfen"><path d="M318.5418,392.9812 C319.0838,361.5483 320.2868,291.78 320.8958,256.425 " fill="none" id="Auftrag der neuen Liste hinzufuegen-to-erhaltene Liste prüfen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="320.9888,251.058,316.8351,259.9881,320.9031,256.0573,324.8339,260.1253,320.9888,251.058" style="stroke:#181818;stroke-width:1.0;"/></g><!--link #12 to erhaltene Liste pr?fen--><g id="link_#12_erhaltene Liste prüfen"><path d="M353.0738,313.157 C347.8708,300.373 337.3908,274.622 329.8808,256.17 " fill="none" id="#12-to-erhaltene Liste prüfen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="327.8488,251.176,327.538,261.02,329.7343,255.8069,334.9474,258.0032,327.8488,251.176" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="25" x="342.2658" y="282.2104">nein</text></g><!--link #9 to neue Liste zur?ckgeben--><g id="link_#9_neue Liste zurückgeben"><path d="M432.9928,242.632 C439.2478,255.441 452.0648,281.685 461.1398,300.267 " fill="none" id="#9-to-neue Liste zurückgeben" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="463.3598,304.813,463.0044,294.9706,461.1655,300.3202,455.8159,298.4814,463.3598,304.813" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="25" x="453.2658" y="282.2104">nein</text></g><!--link neue Liste zur?ckgeben to end--><g id="link_neue Liste zurückgeben_end"><path d="M471.2658,339.1759 C471.2658,355.1231 471.2658,379.2657 471.2658,394.5766 " fill="none" id="neue Liste zurückgeben-to-end" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="471.2658,399.7863,475.2658,390.7863,471.2658,394.7863,467.2658,390.7863,471.2658,399.7863" style="stroke:#181818;stroke-width:1.0;"/></g><!--SRC=[XP2nRi9044Hxlc941KZy0YXzYlGHnHdFdHSk6xI-0ydVHiUFvOpj224XsfsdDwDTh9RhzUPCgoAbejR4LtIQDRGT9O7s8oanwgnWoanyIfi8fv61zokjSJ5Hf-Xajwlleurup2_5GgFX8_jaBk3yM_ZIezivKZCelWzkXvwUe2B2CLk7qf43_Ergg8LuEVHPDedgqjpFrd5S8zfbdzzjPsnvTob5TtY9QIt-7yP8FxofouNS7mEheG-BrV8F]--></g></svg>
\ No newline at end of file
diff --git a/Semester_2/Einheit_03/Pics/Greedy_waehlen.svg b/Semester_2/Einheit_03/Pics/Greedy_waehlen.svg
new file mode 100644
index 0000000000000000000000000000000000000000..823952903d8d58742bd60a1ee7371b57054fa22f
--- /dev/null
+++ b/Semester_2/Einheit_03/Pics/Greedy_waehlen.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="windows-1252" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentStyleType="text/css" height="357px" preserveAspectRatio="none" style="width:637px;height:357px;background:#FFFFFF;" version="1.1" viewBox="0 0 637 357" width="637px" zoomAndPan="magnify"><defs/><g><ellipse cx="282.8776" cy="16" fill="#222222" rx="10" ry="10" style="stroke:none;stroke-width:1.0;"/><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="295" x="135.3776" y="67"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="275" x="145.3776" y="88.1387">ersten Auftrag der erhaltenen Liste speichern</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="152" x="206.8776" y="142"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="132" x="216.8776" y="163.1387">erhaltene Liste prüfen</text><g id="elem_#7"><polygon fill="#F1F1F1" points="390.8776,147,402.8776,159,390.8776,171,378.8776,159,390.8776,147" style="stroke:#181818;stroke-width:0.5;"/></g><g id="elem_#10"><polygon fill="#F1F1F1" points="317.8776,235,329.8776,247,317.8776,259,305.8776,247,317.8776,235" style="stroke:#181818;stroke-width:0.5;"/></g><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="256" x="166.8776" y="318"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="236" x="176.8776" y="339.1387">aktuell gespeicherten Auftrag ersetzen</text><rect fill="#F1F1F1" height="33.9688" rx="12.5" ry="12.5" style="stroke:#181818;stroke-width:0.5;" width="281" x="350.3776" y="230"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacing" textLength="261" x="360.3776" y="251.1387">aktuell gespeicherten Auftrag zurückgeben</text><ellipse cx="490.8776" cy="335" fill="none" rx="10" ry="10" style="stroke:#222222;stroke-width:1.0;"/><ellipse cx="491.3776" cy="335.5" fill="#222222" rx="6" ry="6" style="stroke:none;stroke-width:1.0;"/><!--link start to ersten Auftrag der erhaltenen Liste speichern--><g id="link_start_ersten Auftrag der erhaltenen Liste speichern"><path d="M282.8776,26.177 C282.8776,35.269 282.8776,49.527 282.8776,61.485 " fill="none" id="start-to-ersten Auftrag der erhaltenen Liste speichern" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="282.8776,66.791,286.8776,57.791,282.8776,61.791,278.8776,57.791,282.8776,66.791" style="stroke:#181818;stroke-width:1.0;"/></g><!--link ersten Auftrag der erhaltenen Liste speichern to erhaltene Liste pr?fen--><g id="link_ersten Auftrag der erhaltenen Liste speichern_erhaltene Liste prüfen"><path d="M282.8776,101.201 C282.8776,111.692 282.8776,125.463 282.8776,136.818 " fill="none" id="ersten Auftrag der erhaltenen Liste speichern-to-erhaltene Liste prüfen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="282.8776,141.844,286.8776,132.844,282.8776,136.844,278.8776,132.844,282.8776,141.844" style="stroke:#181818;stroke-width:1.0;"/></g><!--link erhaltene Liste pr?fen to #7--><g id="link_erhaltene Liste prüfen_#7"><path d="M359.2366,159 C363.9566,159 368.6766,159 373.3956,159 " fill="none" id="erhaltene Liste prüfen-to-#7" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="378.5176,159,369.5176,155,373.5176,159,369.5176,163,378.5176,159" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="164" x="410.7261" y="154.6215">weiterer Auftrag vorhanden?</text></g><!--link #7 to #10--><g id="link_#7_#10"><path d="M385.6276,166.185 C373.2106,180.813 341.9326,217.66 326.6106,235.712 " fill="none" id="#7-to-#10" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="323.0796,239.871,331.9536,235.5987,326.3156,236.0593,325.855,230.4213,323.0796,239.871" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="10" x="359.8776" y="207.2104">ja</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="292" x="6" y="235.8145">Auftrag ist besser als aktuell gespeicherter Auftrag</text></g><!--link #10 to aktuell gespeicherten Auftrag ersetzen--><g id="link_#10_aktuell gespeicherten Auftrag ersetzen"><path d="M315.5026,256.8796 C311.9986,269.9816 305.3396,294.879 300.5346,312.8466 " fill="none" id="#10-to-aktuell gespeicherten Auftrag ersetzen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="299.2326,317.715,305.4225,310.0543,300.5247,312.8848,297.6942,307.987,299.2326,317.715" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="10" x="308.8776" y="295.2104">ja</text></g><!--link aktuell gespeicherten Auftrag ersetzen to erhaltene Liste pr?fen--><g id="link_aktuell gespeicherten Auftrag ersetzen_erhaltene Liste prüfen"><path d="M293.7726,317.9812 C291.6046,286.5483 286.7926,216.78 284.3546,181.425 " fill="none" id="aktuell gespeicherten Auftrag ersetzen-to-erhaltene Liste prüfen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="283.9846,176.058,280.6138,185.312,284.3289,181.0461,288.5948,184.7612,283.9846,176.058" style="stroke:#181818;stroke-width:1.0;"/></g><!--link #10 to erhaltene Liste pr?fen--><g id="link_#10_erhaltene Liste prüfen"><path d="M314.6856,238.157 C309.4826,225.373 299.0026,199.622 291.4926,181.17 " fill="none" id="#10-to-erhaltene Liste prüfen" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="289.4606,176.176,289.1498,186.02,291.3461,180.8069,296.5592,183.0032,289.4606,176.176" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="25" x="303.8776" y="207.2104">nein</text></g><!--link #7 to aktuell gespeicherten Auftrag zur?ckgeben--><g id="link_#7_aktuell gespeicherten Auftrag zurückgeben"><path d="M396.8336,165.122 C410.5856,176.949 445.1466,206.672 468.3176,226.599 " fill="none" id="#7-to-aktuell gespeicherten Auftrag zurückgeben" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="472.2186,229.953,468.0023,221.0523,468.4274,226.6932,462.7865,227.1183,472.2186,229.953" style="stroke:#181818;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacing" textLength="25" x="446.8776" y="207.2104">nein</text></g><!--link aktuell gespeicherten Auftrag zur?ckgeben to end--><g id="link_aktuell gespeicherten Auftrag zurückgeben_end"><path d="M490.8776,264.1759 C490.8776,280.1231 490.8776,304.2657 490.8776,319.5766 " fill="none" id="aktuell gespeicherten Auftrag zurückgeben-to-end" style="stroke:#181818;stroke-width:1.0;"/><polygon fill="#181818" points="490.8776,324.7863,494.8776,315.7863,490.8776,319.7863,486.8776,315.7863,490.8776,324.7863" style="stroke:#181818;stroke-width:1.0;"/></g><!--SRC=[VOz13e8m44NtdcB22aYu0iQzDp0i2ln2fQca7JJXREwyc2E294RPpd__pKoS9bcMmmU6eyEWsQk6QdY2RvMLeOoFHb8AFKpLmhlTL9ZJEUpzuwuXKMuqHJSOXXV98hnUX7Srt3uYRZ4fJcTLq8jU815HYH2afsmWrV40Qwd1ifbNuvVc5xk-8z-1HsmU3XimwHoCA-WlvcgZFp3DzFRwSP1orJKetoTGd2PF]--></g></svg>
\ No newline at end of file
diff --git a/Semester_2/Einheit_03/Pics/Komplexitaetsklassen.png b/Semester_2/Einheit_03/Pics/Komplexitaetsklassen.png
new file mode 100644
index 0000000000000000000000000000000000000000..36edd4ffcb576f732f11171784cfad248ca3190f
Binary files /dev/null and b/Semester_2/Einheit_03/Pics/Komplexitaetsklassen.png differ
diff --git a/Semester_2/Einheit_03/Uebung_3.ipynb b/Semester_2/Einheit_03/Uebung_3.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..894d15a843c3dc03ecce1dbf02eb9af223d2f626
--- /dev/null
+++ b/Semester_2/Einheit_03/Uebung_3.ipynb
@@ -0,0 +1,256 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "622edf27",
+   "metadata": {},
+   "source": [
+    "# <font color='blue'>**Ãœbung 3 - Greedy-Algorithmus**</font>\n",
+    "## <font color='blue'>**Problemstellung: Belegungsplan für eine Fertigungsmaschine**</font>\n",
+    "### <font color='blue'>**Problembeschreibung**</font>\n",
+    "\n",
+    "Es soll eine Software für eine Fertigungsmaschine entwickelt werden, die aus einer Liste von Aufträgen eine möglichst gewinnbringende Auswahl zusammenstellt. Diese Auswahl muss in einem gegebenen Zeitraum abgearbeitet werden können. Die Aufträge sollen folgende Informationen enthalten:\n",
+    " * Name\n",
+    " * Wert\n",
+    " * Dauer\n",
+    " \n",
+    "Die Software muss nicht zwingend die beste Auswahl finden. \n",
+    "\n",
+    "### <font color='blue'>**Modellbildung**</font>\n",
+    "\n",
+    "Diese Problemstellung lässt sich auf das typische \"Rucksackproblem\" zurückführen. Dabei entspricht der Belegungsplan mit begrenzter Zeit dem Rucksack mit begrenztem Gewicht. Die Aufträge entsprechen den Gegenständen und haben ebenfalls einen Wert. Statt Gewicht haben sie eine Dauer.\n",
+    "\n",
+    "Da nicht zwingend die beste Auswahl gefunden werden muss, kann der schnelle Greedy-Algorithmus eingesetzt werden, bei dem der Belegungsplan immer um den nächstbesten zeitlich noch passenden Auftrag erweitert wird. Das Kriterium für den \"besten\" Auftrag muss dabei definiert werden. Für die Problemstellung ist der Wert pro Zeit ein vielversprechendes Kriterium.\n",
+    "\n",
+    "### <font color='blue'>**Algorithmierung**</font>\n",
+    "\n",
+    "Die Aufträge werden als einfache Klasse mit den o.g. Attributen umgesetzt. Dabei erhalten sie die `__init__()`-Methode. Die Klasse Auftrag erhält außerdem eine Implementierung der `__repr__()`-Methode. Wenn diese Methode definiert ist, können Objekte der entsprechenden Klasse mit `print(objekt)` verwendet werden, wobei der in der Methode zusammengestellte String ausgegeben wird.\n",
+    "\n",
+    "Eine weitere Klasse `Maschinenbelegungsplan` verwaltet die Auswahl der Aufträge. Als Attribut hat sie die maximale Planungsdauer `planungsdauer` und eine Liste mit den geplanten Aufträgen. Diese Liste wird von zwei Methoden verwaltet: `zurücksetzen()` (leert die Liste) und `hinzufuegen()`, die der Liste den übergebenen Auftrag hinzufügt, aber nur, wenn dieser zeitlich noch in die verbleibende Zeit passt. Die `__init__()`-Methode setzt die maximale Plandauer. Auch diese Klasse soll eine implementierung von `__repr__()` erhalten, die alle geplanten Aufträge, sowie die Gesamtdauer und Gesamtzeit ausgibt. Die Methoden `get_gesamtwert()` und `get_gesamtdauer()` stellen die entsprechenden Informationen zur Verfügung, die dadurch ermittelt werden, dass über die geplante Liste iteriert und das entsprechende Attribut aller Aufträge zusammengezählt wird.\n",
+    "\n",
+    "Die zentrale Methode `greedy_planen()` erhält eine Liste mit möglichen Aufträgen. Diese Liste wird zunächst kopiert, damit Änderungen in der Liste keine Auswirkungen außerhalb der Methode haben. Nun muss beim Greedy-Algorithmus immer ein Auftrag den geplanten Aufträgen hinzugefügt werden, solange noch Aufträge verfügbar sind, die in die verbleibende Zeit passen. Dazu wird die kopierte Liste gefiltert, sodass sie nur noch Aufträge enthält, die eine kürzere Auftragsdauer als die verbleibende Zeit haben. Dies wird an eine Hilfmethode `_auftraege_filtern()` (wird später beschrieben) ausgelagert. Das vorangestellt `_` signalisiert, dass diese Methode nur von der Klasse selbst, nicht aber \"von außen\" verwendet werden soll. Anschließend beginnt eine Schleife, solange noch Aufträge in der gefilterten Liste vorhanden sind. Der beste Auftrag wird ausgewählt (ausgelagert an die Methode `_waehlen()`, die später beschrieben wird). Der ausgewählte Auftrag wird der Liste der geplanten Aufträge hinzugefügt, und aus der Liste zu planender Aufträge entfernt (dazu steht die Listenmethode `remove(element)`zur Verfügung). Anschließend wird die Liste wieder gefiltert, da sich die verbleibende Zeit geändert hat. Sobald kein Auftrag mehr in der Liste zu planender Aufträge vorhanden ist, ist der Algorithmus beendet. Die Auswahl ist im Attribut `geplante_auftraege` gespeichert und verfügbar. Die Methode `greedy_planen()` ist hier in einem Aktivitätsdiagramm skizziert:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "07ceadb0",
+   "metadata": {},
+   "source": [
+    "![](Pics/greedy_algo.svg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a6e4c8cd",
+   "metadata": {},
+   "source": [
+    "In der internen Hilfmethode `_filter_auftraege()` wird eine leere Liste angelegt. Anschließend wird jeder Auftrag in der übergebenen Liste darauf geprüft, ob die Dauer kürzer als die verbleibende Zeit (maximale Zeit abzüglich der bereits geplanten Aufträge) ist. Falls ja, wird der Auftrag an der neuen Liste hinzugefügt. Zum Schluss wird die gefüllte Liste zurückgegeben. Die Methode `_filter_auftraege()` ist hier in einem Aktivitätsdiagramm skizziert:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e5c67335",
+   "metadata": {},
+   "source": [
+    "![](Pics/Greedy_filter.svg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a96beeb6",
+   "metadata": {},
+   "source": [
+    "In der internen Hilfsmethode `_waehle()` wird der erste Auftrag aus der übergebenen Liste zwischengespeichert. Anschließend wird jeder weitere Auftrag der Liste daraufhin geprüft, ob er \"besser\" als der aktuell gespeicherte Auftrag ist. Bei unserem gewählten Kriterium wird dazu der Quotient aus Wert und Dauer verglichen. Falls der neue Auftrag \"besser\" ist, dann wird der neue Auftrag anstelle des gespeicherten Auftrags gespeichert. Sind alle Aufträge geprüft ist der \"beste\" Auftrag gespeichert und kann zurückgegeben werden. Die Methode `_waehle()` ist hier in einem Aktivitätsdiagramm skizziert:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "2c705209",
+   "metadata": {},
+   "source": [
+    "![](Pics/Greedy_waehlen.svg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "54a0eed7",
+   "metadata": {},
+   "source": [
+    "Die gesamte Klassenstruktur in einem UML-Diagramm:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f3742ac0",
+   "metadata": {},
+   "source": [
+    "![](Pics/Greedy.svg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "cc7329cb",
+   "metadata": {},
+   "source": [
+    "### <font color='blue'>**Umsetzung**</font>\n",
+    "\n",
+    "Auftrag:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "30263737",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class Auftrag:\n",
+    "    def __init__(self, \"?\"):\n",
+    "        \"?\"\n",
+    "    \n",
+    "    def __repr__(self):\n",
+    "        return self.name + \", Wert: \" + \"?\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0f2aa2d6",
+   "metadata": {},
+   "source": [
+    "Maschinenbelegungsplan: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "694c2e0b",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class Maschinenbelegungsplan:\n",
+    "    def __init__(self, planungsdauer):\n",
+    "        \"?\"\n",
+    "        \n",
+    "    def get_gesamtwert(self):\n",
+    "        \"?\"\n",
+    "    \n",
+    "    def get_gesamtdauer(self):\n",
+    "        \"?\"\n",
+    "    \n",
+    "    def zuruecksetzen(self):\n",
+    "        \"?\"\n",
+    "        \n",
+    "    def hinzufuegen(self, auftrag):\n",
+    "        \"?\"\n",
+    "    \n",
+    "    def _filter_auftraege(self, auftraege):\n",
+    "        \"?\"\n",
+    "                \n",
+    "    \n",
+    "    def _waehle(self, auftraege):\n",
+    "        \"?\"\n",
+    "    \n",
+    "    def greedy_planen(self, ext_auftraege):\n",
+    "        \"?\"\n",
+    "    \n",
+    "    def __repr__(self):\n",
+    "        ausgabe = \"Der Maschinenbelegungsplan enthaelt:\\n\"\n",
+    "        for auftrag in self.geplante_auftraege:\n",
+    "            ausgabe += str(auftrag)\n",
+    "        ausgabe += \"Gesamtwert: \" + str(self.get_gesamtwert()) + \"\\nGesamtdauer: \" + str(self.get_gesamtdauer()) + \"\\n\"\n",
+    "        return ausgabe\n",
+    "        "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "188af0d7",
+   "metadata": {},
+   "source": [
+    "### <font color='blue'>**Anwendung**</font>\n",
+    "\n",
+    "In diesem Test kann die Implementierung ohne den Greedy-Algorithmus getestet werden. Die Methoden `greedy_planen()`, `_filter_auftraege()` und `_waehle()` werden noch nicht verwendet. Erweitere den Test gerne um mehreren Aufträgen."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b528354b",
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [],
+   "source": [
+    "A1 = Auftrag(\"Beispielauftrag\", 50, 20)\n",
+    "print(A1)\n",
+    "\n",
+    "masch1 = Maschinenbelegungsplan(100)\n",
+    "masch1.hinzufuegen(A1)\n",
+    "print(masch1)\n",
+    "masch1.zuruecksetzen()\n",
+    "print(masch1)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5bb0b4ff",
+   "metadata": {},
+   "source": [
+    "In diesem Test wird der Greedy Algorithmus mit einer Reihe von Aufträgen geprüft. Füge gerne weitere Aufträge hinzu odere ändere die Daten, um verschiedene Ergebnisse zu ermitteln."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "649ac8f6",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# Bei dem folgenden Test und dem Kriterium Wert/Zeit sollte das Ergebnis die Auftraege 2,4,5,6 enthalten.\n",
+    "A1 = Auftrag(\"Auftrag 1\", 40, 100)\n",
+    "A2 = Auftrag(\"Auftrag 2\", 35, 50)\n",
+    "A3 = Auftrag(\"Auftrag 3\", 18, 45)\n",
+    "A4 = Auftrag(\"Auftrag 4\", 4, 20)\n",
+    "A5 = Auftrag(\"Auftrag 5\", 10, 10)\n",
+    "A6 = Auftrag(\"Auftrag 6\", 2, 5)\n",
+    "\n",
+    "a_liste = [A1, A2, A3, A4, A5, A6]\n",
+    "\n",
+    "masch1.zuruecksetzen()\n",
+    "masch1.greedy_planen(a_liste)\n",
+    "print(masch1)\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c0846c79",
+   "metadata": {},
+   "source": [
+    "### <font color='blue'>**Anregungen zum selbst Programmieren:**</font>\n",
+    "* Beim Greedy-Algorithmus können verschiedene Bewertungskriterien zum Einsatz kommen, z.B. der höchste Wert und die kleinste Dauer (wir verwenden bisher Wert/Dauer). Füge mehrere Abwandlungen der `_waehle()` Methode hinzu, die nach diesen anderen Kriterien sortieren. Das zu verwendende Kriterium soll der Methode `greedy_planen()` als zusätzliches Argument übergeben werden. Abhängig von diesem Argument soll eine entsprechende `_waehle()`-Methode verwendet werden. Vergleiche die erhaltenen Auswahlen mit dem \"Wert pro Dauer\"-Kriterium. \n",
+    "* Verbinde das Ergebnis dieser Übung mit der letzten Übung, sodass die Maschine die Warteschlange entsprechend der Ergebnisse des Greedy-Algorithmus plant. Überlege dir dazu eine Programmarchitektur (z.B. ob der Belegungsplan innerhalb der Maschine gespeichert sein soll). Hier gibt es viele verschiedene Möglichkeiten. Teilweise sind Anpassungen erforderlich (z.B. da wir in dieser Übung den Aufträgen nur die für den Algorithmus relevanten Informationen gegeben haben. In der anderen Übung waren mehr Daten erforderlich)."
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.7"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/Semester_2/Einheit_03/Uebung_3_LSG.ipynb b/Semester_2/Einheit_03/Uebung_3_LSG.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..ea047ca7705e9bda94c80f8b43ca4a77f72ac689
--- /dev/null
+++ b/Semester_2/Einheit_03/Uebung_3_LSG.ipynb
@@ -0,0 +1,318 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "622edf27",
+   "metadata": {},
+   "source": [
+    "# <font color='blue'>**Ãœbung 3 - Greedy-Algorithmus**</font>\n",
+    "## <font color='blue'>**Problemstellung: Belegungsplan für eine Fertigungsmaschine**</font>\n",
+    "### <font color='blue'>**Problembeschreibung**</font>\n",
+    "\n",
+    "Es soll eine Software für eine Fertigungsmaschine entwickelt werden, die aus einer Liste von Aufträgen eine möglichst gewinnbringende Auswahl zusammenstellt. Diese Auswahl muss in einem gegebenen Zeitraum abgearbeitet werden können. Die Aufträge sollen folgende Informationen enthalten:\n",
+    " * Name\n",
+    " * Wert\n",
+    " * Dauer\n",
+    " \n",
+    "Die Software muss nicht zwingend die beste Auswahl finden. \n",
+    "\n",
+    "### <font color='blue'>**Modellbildung**</font>\n",
+    "\n",
+    "Diese Problemstellung lässt sich auf das typische \"Rucksackproblem\" zurückführen. Dabei entspricht der Belegungsplan mit begrenzter Zeit dem Rucksack mit begrenztem Gewicht. Die Aufträge entsprechen den Gegenständen und haben ebenfalls einen Wert. Statt Gewicht haben sie eine Dauer.\n",
+    "\n",
+    "Da nicht zwingend die beste Auswahl gefunden werden muss, kann der schnelle Greedy-Algorithmus eingesetzt werden, bei dem der Belegungsplan immer um den nächstbesten zeitlich noch passenden Auftrag erweitert wird. Das Kriterium für den \"besten\" Auftrag muss dabei definiert werden. Für die Problemstellung ist der Wert pro Zeit ein vielversprechendes Kriterium.\n",
+    "\n",
+    "### <font color='blue'>**Algorithmierung**</font>\n",
+    "\n",
+    "Die Aufträge werden als einfache Klasse mit den o.g. Attributen umgesetzt. Dabei erhalten sie die `__init__()`-Methode. Die Klasse Auftrag erhält außerdem eine Implementierung der `__repr__()`-Methode. Wenn diese Methode definiert ist, können Objekte der entsprechenden Klasse mit `print(objekt)` verwendet werden, wobei der in der Methode zusammengestellte String ausgegeben wird.\n",
+    "\n",
+    "Eine weitere Klasse `Maschinenbelegungsplan` verwaltet die Auswahl der Aufträge. Als Attribut hat sie die maximale Planungsdauer `planungsdauer` und eine Liste mit den geplanten Aufträgen. Diese Liste wird von zwei Methoden verwaltet: `zurücksetzen()` (leert die Liste) und `hinzufuegen()`, die der Liste den übergebenen Auftrag hinzufügt, aber nur, wenn dieser zeitlich noch in die verbleibende Zeit passt. Die `__init__()`-Methode setzt die maximale Plandauer. Auch diese Klasse soll eine implementierung von `__repr__()` erhalten, die alle geplanten Aufträge, sowie die Gesamtdauer und Gesamtzeit ausgibt. Die Methoden `get_gesamtwert()` und `get_gesamtdauer()` stellen die entsprechenden Informationen zur Verfügung, die dadurch ermittelt werden, dass über die geplante Liste iteriert und das entsprechende Attribut aller Aufträge zusammengezählt wird.\n",
+    "\n",
+    "Die zentrale Methode `greedy_planen()` erhält eine Liste mit möglichen Aufträgen. Diese Liste wird zunächst kopiert, damit Änderungen in der Liste keine Auswirkungen außerhalb der Methode haben. Nun muss beim Greedy-Algorithmus immer ein Auftrag den geplanten Aufträgen hinzugefügt werden, solange noch Aufträge verfügbar sind, die in die verbleibende Zeit passen. Dazu wird die kopierte Liste gefiltert, sodass sie nur noch Aufträge enthält, die eine kürzere Auftragsdauer als die verbleibende Zeit haben. Dies wird an eine Hilfmethode `_auftraege_filtern()` (wird später beschrieben) ausgelagert. Das vorangestellt `_` signalisiert, dass diese Methode nur von der Klasse selbst, nicht aber \"von außen\" verwendet werden soll. Anschließend beginnt eine Schleife, solange noch Aufträge in der gefilterten Liste vorhanden sind. Der beste Auftrag wird ausgewählt (ausgelagert an die Methode `_waehlen()`, die später beschrieben wird). Der ausgewählte Auftrag wird der Liste der geplanten Aufträge hinzugefügt, und aus der Liste zu planender Aufträge entfernt (dazu steht die Listenmethode `remove(element)`zur Verfügung). Anschließend wird die Liste wieder gefiltert, da sich die verbleibende Zeit geändert hat. Sobald kein Auftrag mehr in der Liste zu planender Aufträge vorhanden ist, ist der Algorithmus beendet. Die Auswahl ist im Attribut `geplante_auftraege` gespeichert und verfügbar. Die Methode `greedy_planen()` ist hier in einem Aktivitätsdiagramm skizziert:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "07ceadb0",
+   "metadata": {},
+   "source": [
+    "![](Pics/greedy_algo.svg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a6e4c8cd",
+   "metadata": {},
+   "source": [
+    "In der internen Hilfmethode `_filter_auftraege()` wird eine leere Liste angelegt. Anschließend wird jeder Auftrag in der übergebenen Liste darauf geprüft, ob die Dauer kürzer als die verbleibende Zeit (maximale Zeit abzüglich der bereits geplanten Aufträge) ist. Falls ja, wird der Auftrag an der neuen Liste hinzugefügt. Zum Schluss wird die gefüllte Liste zurückgegeben. Die Methode `_filter_auftraege()` ist hier in einem Aktivitätsdiagramm skizziert:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "e5c67335",
+   "metadata": {},
+   "source": [
+    "![](Pics/Greedy_filter.svg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "a96beeb6",
+   "metadata": {},
+   "source": [
+    "In der internen Hilfsmethode `_waehle()` wird der erste Auftrag aus der übergebenen Liste zwischengespeichert. Anschließend wird jeder weitere Auftrag der Liste daraufhin geprüft, ob er \"besser\" als der aktuell gespeicherte Auftrag ist. Bei unserem gewählten Kriterium wird dazu der Quotient aus Wert und Dauer verglichen. Falls der neue Auftrag \"besser\" ist, dann wird der neue Auftrag anstelle des gespeicherten Auftrags gespeichert. Sind alle Aufträge geprüft ist der \"beste\" Auftrag gespeichert und kann zurückgegeben werden. Die Methode `_waehle()` ist hier in einem Aktivitätsdiagramm skizziert:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "2c705209",
+   "metadata": {},
+   "source": [
+    "![](Pics/Greedy_waehlen.svg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "54a0eed7",
+   "metadata": {},
+   "source": [
+    "Die gesamte Klassenstruktur in einem UML-Diagramm:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f3742ac0",
+   "metadata": {},
+   "source": [
+    "![](Pics/Greedy.svg)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "cc7329cb",
+   "metadata": {},
+   "source": [
+    "### <font color='blue'>**Umsetzung**</font>\n",
+    "\n",
+    "Auftrag:"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "30263737",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class Auftrag:\n",
+    "    def __init__(self, name, wert, dauer):\n",
+    "        self.name = name\n",
+    "        self.wert = wert\n",
+    "        self.dauer = dauer\n",
+    "    \n",
+    "    def __repr__(self):\n",
+    "        return self.name + \", Wert: \" + str(self.wert) + \" Dauer: \" + str(self.dauer) +\"\\n\""
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "0f2aa2d6",
+   "metadata": {},
+   "source": [
+    "Maschinenbelegungsplan: "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "694c2e0b",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class Maschinenbelegungsplan:\n",
+    "    def __init__(self, planungsdauer):\n",
+    "        self.planungsdauer = planungsdauer\n",
+    "        self.geplante_auftraege = []\n",
+    "        \n",
+    "    def get_gesamtwert(self):\n",
+    "        w = 0\n",
+    "        for auftrag in self.geplante_auftraege:\n",
+    "            w += auftrag.wert\n",
+    "        return w\n",
+    "    \n",
+    "    def get_gesamtdauer(self):\n",
+    "        t = 0\n",
+    "        for auftrag in self.geplante_auftraege:\n",
+    "            t += auftrag.dauer\n",
+    "        return t\n",
+    "    \n",
+    "    def zuruecksetzen(self):\n",
+    "        self.geplante_auftraege = []\n",
+    "        \n",
+    "    def hinzufuegen(self, auftrag):\n",
+    "        if self.planungsdauer - self.get_gesamtdauer() >= auftrag.dauer:\n",
+    "            self.geplante_auftraege.append(auftrag)\n",
+    "        else:\n",
+    "            print(\"Der Auftrag dauert zu lange für die verbleibende Zeit\")\n",
+    "    \n",
+    "    def _filter_auftraege(self, auftraege):\n",
+    "        restzeit = self.planungsdauer - self.get_gesamtdauer()\n",
+    "        temp = []\n",
+    "        for auftrag in auftraege:\n",
+    "            if auftrag.dauer <= restzeit:\n",
+    "                temp.append(auftrag)\n",
+    "        return temp\n",
+    "        # Alternative zu temp und expliziter Schleife mit list-comprehension\n",
+    "        # return [auftrag for auftrag in auftraege if auftrag.dauer <= restzeit]\n",
+    "                \n",
+    "    \n",
+    "    def _waehle(self, auftraege):\n",
+    "        temp_auswahl = auftraege[0]\n",
+    "        for auftrag in auftraege[1:]:\n",
+    "            if auftrag.wert / auftrag.dauer > temp_auswahl.wert / temp_auswahl.dauer:\n",
+    "                temp_auswahl = auftrag\n",
+    "        return temp_auswahl\n",
+    "    \n",
+    "    def greedy_planen(self, ext_auftraege):\n",
+    "        auftraege = ext_auftraege.copy()\n",
+    "        auftraege = self._filter_auftraege(auftraege)\n",
+    "        while len(auftraege)>0:\n",
+    "            auswahl = self._waehle(auftraege)\n",
+    "            self.hinzufuegen(auswahl)\n",
+    "            auftraege.remove(auswahl)\n",
+    "            auftraege = self._filter_auftraege(auftraege)\n",
+    "    \n",
+    "    def __repr__(self):\n",
+    "        ausgabe = \"Der Maschinenbelegungsplan enthaelt:\\n\"\n",
+    "        for auftrag in self.geplante_auftraege:\n",
+    "            ausgabe += str(auftrag)\n",
+    "        ausgabe += \"Gesamtwert: \" + str(self.get_gesamtwert()) + \"\\nGesamtdauer: \" + str(self.get_gesamtdauer()) + \"\\n\"\n",
+    "        return ausgabe\n",
+    "        "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "188af0d7",
+   "metadata": {},
+   "source": [
+    "### <font color='blue'>**Anwendung**</font>\n",
+    "\n",
+    "In diesem Test kann die Implementierung ohne den Greedy-Algorithmus getestet werden. Die Methoden `greedy_planen()`, `_filter_auftraege()` und `_waehle()` werden noch nicht verwendet. Erweitere den Test gerne um mehreren Aufträgen."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "b528354b",
+   "metadata": {
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Beispielauftrag, Wert: 50 Dauer: 20\n",
+      "\n",
+      "Der Maschinenbelegungsplan enthaelt:\n",
+      "Beispielauftrag, Wert: 50 Dauer: 20\n",
+      "Gesamtwert: 50\n",
+      "Gesamtdauer: 20\n",
+      "\n",
+      "Der Maschinenbelegungsplan enthaelt:\n",
+      "Gesamtwert: 0\n",
+      "Gesamtdauer: 0\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "A1 = Auftrag(\"Beispielauftrag\", 50, 20)\n",
+    "print(A1)\n",
+    "\n",
+    "masch1 = Maschinenbelegungsplan(100)\n",
+    "masch1.hinzufuegen(A1)\n",
+    "print(masch1)\n",
+    "masch1.zuruecksetzen()\n",
+    "print(masch1)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5bb0b4ff",
+   "metadata": {},
+   "source": [
+    "In diesem Test wird der Greedy Algorithmus mit einer Reihe von Aufträgen geprüft. Füge gerne weitere Aufträge hinzu odere ändere die Daten, um verschiedene Ergebnisse zu ermitteln."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "649ac8f6",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Der Maschinenbelegungsplan enthaelt:\n",
+      "Auftrag 5, Wert: 10 Dauer: 10\n",
+      "Auftrag 2, Wert: 35 Dauer: 50\n",
+      "Auftrag 6, Wert: 2 Dauer: 5\n",
+      "Auftrag 4, Wert: 4 Dauer: 20\n",
+      "Gesamtwert: 51\n",
+      "Gesamtdauer: 85\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Bei dem folgenden Test und dem Kriterium Wert/Zeit sollte das Ergebnis die Auftraege 2,4,5,6 enthalten.\n",
+    "A1 = Auftrag(\"Auftrag 1\", 40, 100)\n",
+    "A2 = Auftrag(\"Auftrag 2\", 35, 50)\n",
+    "A3 = Auftrag(\"Auftrag 3\", 18, 45)\n",
+    "A4 = Auftrag(\"Auftrag 4\", 4, 20)\n",
+    "A5 = Auftrag(\"Auftrag 5\", 10, 10)\n",
+    "A6 = Auftrag(\"Auftrag 6\", 2, 5)\n",
+    "\n",
+    "a_liste = [A1, A2, A3, A4, A5, A6]\n",
+    "\n",
+    "masch1.zuruecksetzen()\n",
+    "masch1.greedy_planen(a_liste)\n",
+    "print(masch1)\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c0846c79",
+   "metadata": {},
+   "source": [
+    "### <font color='blue'>**Anregungen zum selbst Programmieren:**</font>\n",
+    "* Beim Greedy-Algorithmus können verschiedene Bewertungskriterien zum Einsatz kommen, z.B. der höchste Wert und die kleinste Dauer (wir verwenden bisher Wert/Dauer). Füge mehrere Abwandlungen der `_waehle()` Methode hinzu, die nach diesen anderen Kriterien sortieren. Das zu verwendende Kriterium soll der Methode `greedy_planen()` als zusätzliches Argument übergeben werden. Abhängig von diesem Argument soll eine entsprechende `_waehle()`-Methode verwendet werden. Vergleiche die erhaltenen Auswahlen mit dem \"Wert pro Dauer\"-Kriterium. \n",
+    "* Verbinde das Ergebnis dieser Übung mit der letzten Übung, sodass die Maschine die Warteschlange entsprechend der Ergebnisse des Greedy-Algorithmus plant. Überlege dir dazu eine Programmarchitektur (z.B. ob der Belegungsplan innerhalb der Maschine gespeichert sein soll). Hier gibt es viele verschiedene Möglichkeiten. Teilweise sind Anpassungen erforderlich (z.B. da wir in dieser Übung den Aufträgen nur die für den Algorithmus relevanten Informationen gegeben haben. In der anderen Übung waren mehr Daten erforderlich)."
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.7"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}