Informatik II PVK Tag 2 Michael Baumann [email protected] n.ethz.ch/~mbauman | | Themen Theorie 1) Java Basics 2) Theorie: Komplexität und Laufzeit 3) OOP | | 2 Themen Praxis 1) Syntaxbäume 2) Verkettete Listen 3) Stacks 4) Binärsuche 5) Suchbäume 6) Spielbäume 7) Backtracking 8) Rekursion & Divide et impera 9) Simulation 10)Heaps 11)Parallelisierung | | 3 Binärsuche | | 4 Binary Search Fundamentals ● ● Daten ● Tupel aus Key und Nutzdaten ● Sortiert nach Key Finde einen gewissen Key ● Möglichkeit 1: Alle durchgehen: O(n) ● Möglichkeit2: BinarySearch ● O(log n) ● Annahme: Daten ungefähr gleichverteilt | | 5 Idee Binärsuche ● Finde das Element mit Key 22 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 3 4 9 15 17 22 23 24 27 28 32 34 37 38 40 41 27 ● begin: 0 ● end: 16 ● Middle: 16/2 = 8 22 < 27 | | 6 Idee Binärsuche ● Finde das Element mit Key 22 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 3 4 9 15 17 22 23 24 27 28 32 34 37 38 40 41 27 ● begin: 0 ● end: 8 ● middle: 8/2 = 4 17 22 > 17 | | 7 Idee Binärsuche ● Finde das Element mit Key 22 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 3 4 9 15 17 22 23 24 27 28 32 34 37 38 40 41 27 ● begin: 5 ● end: 8 ● middle: 13/2 = 6 17 23 22 < 23 | | 8 Idee Binärsuche ● Finde das Element mit Key 22 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 3 4 9 15 17 22 23 24 27 28 32 34 37 38 40 41 27 ● begin: 5 ● end: 6 ● middle: 13/2 = 5 17 23 22 22 < 23 | | 9 Pseudocode Binärsuche Value b_search(List haystack, Key needle, int begin, int end) { if(begin == end) return null; middle = (begin + end)/2; if(needle == haystack[middle].key) { return haystack[middle].value } else if(needle < haystack[middle].key) { return b_search(haystack, needle, begin, middle); } else { return b_search(haystack, needle, middle+1, end); } Verhindert Endlosschleife, } Falls das Element nicht existiert | | 10 Heuristik der Verteilung ● Wir haben stillschweigend das arithmetische Mittel gewählt middle = (begin + end)/2; ● ● ● Das muss nicht sein, allgemein kann man hier durch 'factor' teilen Idee: Mehr kleine IDs als grosse → Teile durch grössere Zahl, so dass man schneller 'nach links' kommt i.A. Annahme: Daten gleichverteilt → factor = 2 ideal. | | 11 Prüfungsrelevanz ● Von Hand per Binärsuche etwas finden ● In Java aufschreiben ● ● Die Schnittstelle von haystack muss gegeben sein ● Auf Grenzen achten! Bedeutung des Paramters 'factor' | | 12 Suchbäume | | 13 Intermezzo: Binärbäume im Array ● Jeder Knoten hat (max.) 2 Nachfolger ● Die k-te Ebene braucht also Platz für 2^(k-1) Elemente 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 2 2 3 3 3 3 4 4 4 4 4 4 4 4 5 ● Damit können wir den Baum super linear speichern ● Kind1: (index * 2) + 1 ● Kind2: (index * 2) + 2 ● Vater: (index – 1) / 2 | | 14 Binary Search Trees Fundamentals ● ● ● Natürliche Erweiterung der Binärsuche Idee: Lege die Pfade der Binärsuche nach allen möglichen Elementen übereinander Resultat: ● Binärbaum ● Alle Elemente im linken Teilbaum sind kleiner ● Alle im rechten sind grösser | | 15 Suchbaum vs. Heap | | 16 Beispiel Suchbaum 50 10 80 35 51 92 24 | | 17 Operationen im Suchbaum ● isLeaf, hasOneChild ● height ● insert ● find ● remove ● pre-, in-, postOrder | | 18 insert public BinarySearchTree<T> insert(BinarySearchTree<T> tree, int key, T thing) { if (tree == null) { return new BinarySearchTree<T>(key, thing); } if (tree.key == key) { tree.thing = thing; } else if (key < tree.key) { tree.left = insert(tree.left, key, thing); } else { tree.right = insert(tree.right, key, thing); } return tree; } | | 19 insert Beispiel: Füge '68' ein 50 10 80 68 35 51 92 24 | | 20 insert Beispiel: Füge '68' ein 50 10 80 68 35 24 51 92 68 | | 21 remove: Drei Fälle ● Blatt ● ● 1 Kind ● ● Trivial, entferne es einfach Entfernen und Kind an diese Stelle setzen 2 Kinder ● ● Schwieriger Setze das nächstgrössere (kleinstes im rechten Teilbaum) an diese Stelle und entferne das bisherige | | 22 remove: 2 Kinder public BinarySearchTree<T> remove(BinarySearchTree<T> tree, int key) { ... UnlinkSmallestResult<T> result = unlinkSmallest(tree.right); result.smallest.right = result.tree; result.smallest.left = tree.left; return result.smallest; ... } | | 23 remove: Hilfsfunktion unlinkSmallest public UnlinkSmallestResult<T> unlinkSmallest(BinarySearchTree<T> tree) { if (tree.left == null) { return new UnlinkSmallestResult<T>(tree, tree.right); } } Nichts mehr links -> Wir haben das Kleinste gefunden | | 24 remove: Hilfsfunktion unlinkSmallest public UnlinkSmallestResult<T> unlinkSmallest(BinarySearchTree<T> tree) { if (tree.left == null) { return new UnlinkSmallestResult<T>(tree, tree.right); } UnlinkSmallestResult<T> result = unlinkSmallest(tree.left); tree.left = result.tree; return new UnlinkSmallestResult<T>(result.smallest, tree); } Aktualisiere den linken Ast und gib den neuen Teilbaum zurück | | 25 Aufgabe 2 Beispiel: Entferne '24' 50 10 80 35 24 51 92 68 | | 26 Aufgabe 2 Beispiel: Entferne '24' 50 10 80 35 Blatt → Trivial! 51 92 68 | | 27 Aufgabe 2 Beispiel: Entferne '10' 50 10 80 35 51 92 68 | | 28 Aufgabe 2 Beispiel: Entferne '10' 50 35 80 51 Ein Kind → Einfach! 92 68 | | 29 Aufgabe 2 Beispiel: Entferne '50' 50 35 80 51 92 68 | | 30 Aufgabe 2 Beispiel: Entferne '50' ● 50 Finde kleinstes Element im rechten Teilbaum ● 51 35 80 51 92 68 | | 31 Aufgabe 2 Beispiel: Entferne '50' ● ● ● 50 Finde kleinstes Element im rechten Teilbaum 51 35 Entferne dieses ● 51 Das ist einfacher ● Warum? 80 51 92 68 | | 32 Aufgabe 2 Beispiel: Entferne '50' ● ● ● 51 Finde kleinstes Element im rechten Teilbaum 51 Entferne dieses ● Das ist einfacher ● 35 80 68 92 Warum? | | 33 Aufgabe 2 Beispiel: Entferne '50' ● ● ● 51 Entferne dieses ● Das ist einfacher ● ● 51 Finde kleinstes Element im rechten Teilbaum 35 80 68 92 Warum? Füge es an Stelle des zu entfernenden ein | | 34 Sortieren per Suchbaum ● Beobachtung: Suchbaum inOrder ausgeben → sortiert ● Idee: Sortieren per Suchbaum ● ● Füge alle Elemente in Suchbaum ein ● Gib in inOrder aus Laufzeit: ● Gut durchmischt: O(n*log n) ● Vorsortiert: O(n2) ● Degenerierter Baum: Liste ● Deshalb in der Praxis selten verwendet | | 35 Prüfungsrelevanz ● Darstellung Binärbaum in Array ● Operationen auf Binärbaum ● ● Löschen(!) ● Zumindest von Hand Sortieren per Suchbaum nicht so wichtig | | 36 Spielbäume | | 37 Spielbäume & Spieltheorie ● Aufbau von Spielbäumen ● ● Füge alle möglichen Züge als Kinder des aktuellen Zugs ein Strategie ● Für JEDE Möglichkeit einen Zug wählen ● Eine Kante von jedem Zustand „unseres“ Spielers ● Also nicht nur ein Ast ● Oder gar eine Kante | | 38 Eine Strategie MAX 4 4 4 3 7 7 -5 MIN -2 0 -2 2 0 2 1 MAX 8 7 MIN 8 | | 39 Keine Strategie MAX 4 4 4 3 7 7 -5 MIN -2 0 -2 2 0 2 1 MAX 8 7 MIN 8 | | 40 Gar keine Strategie MAX 4 4 4 3 7 7 -5 MIN -2 0 -2 2 0 2 1 MAX 8 7 MIN 8 | | 41 Minimax ● Zwei Spieler (MIN und MAX) wechseln sich ab ● MAX-Spieler wählt den besten Zug für sich ● MIN-Spieler wählt den schlechtesten Zug für MAX ● Algorithmus ● MAX-Stufe: Wert = max{Werte der Kinder} ● MIN-Stufe: Wert = min{Werte der Kinder} | | 42 Minimax MAX MIN 4 3 7 -5 MAX -2 0 2 1 7 MIN 8 | | 43 Minimax MAX MIN 4 3 7 7 -5 -2 2 0 2 1 MAX 8 7 MIN 8 | | 44 Minimax MAX 4 4 3 7 7 -5 MIN -2 0 -2 2 0 2 1 MAX 8 7 MIN 8 | | 45 Minimax MAX 4 4 4 3 7 7 -5 MIN -2 0 -2 2 0 2 1 MAX 8 7 MIN 8 | | 46 Alpha-Beta ● Manche Teilbäume müssen gar nicht analysiert werden Max Min könnte -1 erreichen Max kann 0 erreichen -> Max wird nicht diesen Zug wählen Min Max Min | | 47 Alpha-Beta: Algorithmus ● Führe ein Intervall [α, β] mit ● Min aktualisiert β (verkleinert es) und gibt β zurück ● Max aktualisiert α (vergrössert es) und gibt α zurück ● Schnitte: ● Max: Neues α ≥ β → β-cut ● Min: Neues β ≤ α → α-cut ● Unser Beispiel: 2 α-cuts | | 48 Alpha-Beta: Üben ● Beispiel auf PVK-Website ● Beispiel sehr detailliert simuliert http://vs.inf.ethz.ch/edu/i2/slides/Info2-ITET-AlphaBeta.pdf ● Java Applet http://www.ocf.berkeley.edu/~yosenl/extras/alphabeta/alphabeta.html | | 49 Prüfungsrelevantes ● Einfacher Spielbaum aufbauen (Tic-Tac-Toe oder so) ● Minimax ausfüllen ● AlphaBeta ● ● ● Richtige Cuts setzen Intervalle und Unterscheidung α/β-Cut wahrscheinlich nicht nötig Möglicherweise Min / Max-Funktion ausfüllen (Lückentext) | | 50 Backtracking | | 51 Späckträcking ● Verbessertes Brute Force ● Grosser Suchraum, so dass Brute Force zu lange braucht ● Probiere nicht alle Möglichkeiten durch ● Brich so bald wie möglich ab... ● ...und gehe einen Schritt zurück. | | 52 Template Backtracking boolean backtrack(data, depth) { if(solved()) { return true; } for(possible_move in data) { make_move(possible_move); if(backtrack(data, depth+1) == true) { return true; } } revert(); return false; //backtracking } | | 53 Vergleich Brute Force ↔ Backtracking ● ● Brute Force führt alle „Züge“ auf einmal aus ● Merkt dann, dass es nicht geht... ● ...und versucht die nächste Kombination Backtracking macht jeden Zug einzeln ● Merkt, dass es nicht geht... ● ...und geht einen Zug zurück | | 54 Bsp. Sudoku: Brute Force 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 | | 55 Bsp. Sudoku: Brute Force 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 | | 56 Bsp. Sudoku: Brute Force 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 3 | | 57 Bsp. Sudoku: Backtracking 1 2 4 8 9 ? | | 58 Bsp. Sudoku: Backtracking 1 2 6 4 9 8 ... | | 59 Prüfungsrelevantes ● Idee Backtracking ● ● Schritt für Schritt, Abbruch sobald hoffnungslos Backtracking ↔ Brute Force | | 60 Divide et impera | | 61 Divide et impera ● Kennt ihr bestens ● Problem ist schwierig ● Führe es zurück auf ein kleineres Problem, das einfacher zu lösen ist ● ● IdR. rekursiv Löse dieses und mache wenige Anpassungen | | 62 Beispiel Divide et impera: Mergesort ● Sehr wichtig: Eines der häufigsten Sortierverfahren ● InPlace möglich ● Algorithmus ● Liste leer / 1 Element → return (fertig) ● Teile die Liste in zwei Teillisten ● Sortiere diese ● Füge die sortierten Listen in eine grosse zusammen ● Nimm jeweils das kleinste von beiden 63 Mergesort private ArrayList<T> mergesort(ArrayList<T> items, int begin, int end) { if (begin == end) { return new ArrayList<T>(); } if (begin + 1 == end) { ArrayList<T> result = new ArrayList<T>(); result.add(items.get(begin)); return result; } int middle = begin + (end­begin) / 2; ArrayList<T> left = mergesort(items, begin, middle); ArrayList<T> right = mergesort(items, middle, end); return merge(left, right); } | | 64 Mergesort private ArrayList<T> merge(ArrayList<T> left, ArrayList<T> right) { int leftIdx = 0; int rightIdx = 0; ArrayList<T> sorted = new ArrayList<T>(); while(true) { if (leftIdx == left.size()) { sorted.addAll(right.subList(rightIdx, right.size())); return sorted; } if (rightIdx == right.size()) { sorted.addAll(left.subList(leftIdx, left.size())); return sorted; } if (left.get(leftIdx).compareTo(right.get(rightIdx)) < 0) sorted.add(left.get(leftIdx++)); else sorted.add(right.get(rightIdx++)); } } | | 65 Prüfungsrelevantes ● Idee Divide et impera ● Mergesort | | 66 Simulation | | 67 Simulation ● Komplexe Vorgänge per Computer nachspielen ● Möglichst schnell genaues Ergebnis ● Zwei Arten ● Zeitgesteuert ● Ereignisgesteuert | | 68 Zeitgesteuerte Simulation ● Zustand zur Zeit tk bekannt ● Berechne Änderungen tk→tk+1 ● Wiederhole, so lange tk > tmax | | 69 Probleme Zeitgesteuerte Simulation ● Häufig passiert lange Zeit gar nichts... ● ...und dann viel auf einmal ● ● Bei konstantem Zeitschritt verlieren wir in den „Totzeiten“ viel Rechenzeit Möglichkeiten ● Schrittweitensteuerung (i.A. schwierig) ● Ereignisgesteuerte Simulation | | 70 Ereignisgesteuerte Simulation ● Idee: Liste von Ereignissen mit Zeitpunkt ● Bei Eintreffen von Ereignis werden neue berechnet ● Eigenschaften ● Keine verschwendete Rechenzeit ● Kausalität nicht gegeben ● ● Bei guter Modellierung nicht wichtig Beispiel Telefonzentrale | | 71 Prüfungsrelevantes ● Vor- & Nachteile Zeit- & Ereignisgesteuerte Simulation ● Implementation einer einfachen zeitgesteuerten Simulation | | 72 Heaps | | 73 Heap Fundamentals ● Einsatzzweck von Heaps: Priority-Queues ● ● Ereignisgesteuerte Simulationen! Struktur ● Binärbaum ● Alle Kinder sind kleiner (Max-Heap)... ● ...oder grösser (Min-Heap) als der Vater ● Immer kompakt ● Kann im Gegensatz zu Suchbaum nicht zur Liste degenerieren | | 74 Suchbaum vs. Heap | | 75 Das ist ein Heap 1 4 7 9 8 51 29 24 | | 76 Das ist kein Heap 1 4 7 9 8 51 29 24 | | 77 Operationen im Heap ● Insert: O(log n) ● ● ● Füge das Element am Schluss des Heaps ein (Heap vergrössern) Propagiere es so weit wie möglich nach oben (Vertauschen mit kleinerem Kind) get_min / get_max: O(log n) ● Entferne die Wurzel und gib es zurück ● Setze das letzte Element auf die Wurzel ● Propagiere es so weit wie möglich nach unten | | 78 Insert: Füge '2' ein 1 2 4 7 9 8 51 29 24 | | 79 Insert: Füge '2' ein 1 4 7 24 9 8 51 29 2 | | 80 Insert: Füge '2' ein 1 4 2 24 9 8 51 29 7 | | 81 Insert: Füge '2' ein 1 2 4 24 9 8 51 29 7 | | 82 get_min 1 2 4 24 9 8 51 29 7 | | 83 get_min 7 2 4 9 8 51 29 24 | | 84 get_min 2 7 4 9 8 51 29 24 | | 85 get_min 2 4 7 9 8 51 29 24 | | 86 Insert (Min-Heap) private void insert(ArrayList<T> items, int index) { int father = father_position(index); if(items.get(index).compareTo(items.get(father)) < 0) { swap(items, index, father); insert(items, father); } } | | 87 get_min (Min-Heap) private void sink(ArrayList<Integer> items, int i) { if(leftchild(i) >= n) { return; } int childindex = leftchild(i); if(rightchild(i) < n){ if(items.get(leftchild(i)) < items.get(rightchild(i)) childindex = rightchild(i); } if(items.get(i) < items.get(childindex)){ swap(items, i, childindex); sink(items, childindex, n); } else { return; } } | | 88 Heapsort ● ● Idee ähnlich wie bei sortieren per Suchbaum ● Füge alles einmal ein... ● ...und lese es wieder raus Algorithmus: O(n*log n) ● ● Füge alle Elemente in einen Max-Heap ein Lies das grösste Element aus und füge es VORNE in die sortierte Liste ein ● Alternativ: Min-Heap und hinten einfügen ● In Place-Implementierung: Siehe Serie 12 | | 89 Prüfungsrelevantes ● Definition Heap ● Unterschiede Heap ↔ Suchbaum ● Operationen implementieren können ● ● insert ● get_min Heapsort | | 90 Parallelisierung | | 91 Gleichzeitigkeit, Prozess ↔ Thread ● Gleichzeitigkeit auf zwei Arten erreichbar ● ● ● Mehrere Prozessoren → „wirklich gleichzeitig“ Schnell zwischen allen Prozessen wechseln → erscheinen gleichzeitig Prozess ↔ Thread ● Prozesswechsel sind teuer, deshalb Thread: ● „Leichtgewichtsprozess“ ● Kein Adressraumwechsel etc. ● Mehr Parallelität möglich | | 92 Scheduling ● ● Ein Thread kann CPU freigeben (yield)... ...je nach dem macht das auch des Scheduler (preemptive scheduling) | | 93 Threads in Java ● java.lang.Thread ● start Starte in neuem Thread ● sleep ● run Starte in diesem Thread ● join ● suspend ● getPriority ● stop ● setPriority ● resume ● setDaemon ● wait ● yield Warte, bis Thread fertig | | 94 Race conditions, Critical sections ● Zwei Prozesse greifen auf die gleichen Daten zu ● Reihenfolge der Zugriffe unbekannt ● Unabhängig von der Reihenfolge muss der Zustand konsistent sein. ● Es dürfen keine Änderungen verloren gehen ● Lösung: synchronized | | 95 synchronized ● ● Ist ein Prozess in einem synchronized-Block, kann kein weiterer in einen verwandten synchronized-Block kommen Benötigen ein lock-Objekt ● Muss für alle Threads das gleiche sein static Object lock = new Object(); ... synchronized(lock) { ... } ● Aufpassen: Starvation durch Mutex! | | 96 Prüfungsrelevantes ● Zustände Prozess, Thread ● Übergangsoperationen ● Race conditions, Critical sections ● synchronized-Schlüsselwort | | 97