Prof. Dr. V. Linnemann Universität zu Lübeck Institut für Informationssysteme Lübeck, den 20. Juli 2010 Algorithmen und Datenstrukturen Sommersemester 2010 1. Klausur Lösungen Lösung 1: Laufzeitstack Wir nehmen an, dass die main - Methode der folgenden Klasse aufgerufen wird. Was bewirkt die main - Methode ? Geben Sie den Laufzeitstack jeweils zu Beginn eines Aufrufs der Methode fastfibrek an. Verwenden Sie als Bezeichnung der Rückkehradressen den jeweils angegebenen Kommentar. public class Fiblinearrekursiv { public static long fastfibrek (int nminusiplus1, long fibi, long fibiminus1) { /* Laufzeitstack hier */ if(nminusiplus1==1) // i==n return fibi; return fastfibrek( nminusiplus1-1,fibi+fibiminus1,fibi) /* B */; } public static void main(String[] args){ long ergebnis = fastfibrek(5,1,0) /* A */; System.out.println(ergebnis); } } (6 Punkte) Lösung: Es wird die 5. Fibonacci-Zahl ausgegeben, d.h. es wird der Wert 5 ausgegeben. 1/20 Laufzeitstack: Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse 5 1 0 A Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse 5 1 0 A 4 1 1 B 3 2 1 B 2 3 2 B Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse 2/20 5 1 0 A 4 1 1 B 3 2 1 B 2 3 2 B 1 5 3 B 5 1 0 A 4 1 1 B Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse Ergebnis nminusiplus1 fibi fibiminus1 Rückkehradresse 5 1 0 A 4 1 1 B 3 2 1 B Lösung 2: Adjazenzmatrix und Backtracking mit Rekursion a.) Zeichnen Sie den durch die folgende Adjazenzmatrix A gegebenen gerichteten Graphen, wobei T den Wert true bezeichnet und die false - Werte der Übersicht halber hier leer dargestellt sind. A[i][j] == true bedeutet, dass im Graphen ein Pfeil von i nach j existiert. A 0 1 2 3 4 5 6 7 8 0 T 1 T T 2 3 T T T T T 4 5 T T T T T 6 7 8 (3 Punkte) T T T T T T T b.) In dieser Teilaufgabe sollen Sie einen Weg in einem durch eine Adjazenzmatrix beschriebenen gerichteten Graphen von einem Startknoten zu einem Zielknoten rekursiv mit Backtracking finden. Die Knoten sind beginnend bei 0 durchnummeriert. Es genügt, einen Weg zu finden, die Angabe des kürzesten Weges ist hier nicht gefordert. Realisieren Sie in der nachfolgenden Klasse die Methode probieren. In der Methode matrix1 wird das Feld matrix mit der Adjazenzmatrix aus Aufgabenteil a.) gesetzt. Im Beispiel ist ein Weg vom Knoten 0 zum Knoten 8 gesucht. Hier gibt es nur einen Weg ohne Zyklen, der offenbar durch die Knotenfolge 013578 beschrieben wird. In der nachfolgenden Klasse gibt es für zyklenfreie Wege im Graphen ein Feld weg, das so viele Elemente hat wie der Graph Knoten besitzt. Die Variable weglaenge gibt an, wie lang ein aktuell gefundener Weg ist, d.h. wie viele Elemente des Feldes weg gesetzt sind. Ihre rekursive probieren - Methode soll das Feld weg und die Variable weglaenge geeignet setzen, d.h. für das Beispiel soll weg mit den obigen Werten gefüllt und die Variable weglaenge mit dem Wert 6 gesetzt werden.. Achten Sie darauf, dass Ihre probieren-Methode Zyklen im Graphen geeignet behandelt und dass sie auch den Fall abdeckt, dass es keinen Weg vom Startknoten zum Zielknoten gibt. Erläutern Sie Ihre Lösung durch geeigneten Kommentar, so dass der Algorithmus ersichtlich ist. 3/20 Hinweis zum Aufwand: Es gibt eine Lösung, die einschließlich Kommentar nur 27 Zeilen enthält. public class Labyrinth { // Adjazenzmatrix fuer den Graphen private static boolean matrix[][]; // Anzahl der Knoten im Graphen private static int knotenzahl; // bisher gefundener Weg private static int[] weg; // Laenge des bisher gefundenen Weges, d.h. // weg ist bis weg[weglaenge-1] gesetzt private static int weglaenge; // Startknoten fuer Wegsuche private static int start; // Zielknoten fuer Wegsuche private static int ziel; /** * probieren sucht einen Weg bis zum Zielknoten * ausgehend von knoten. * * weglaenge und weg enthalten bei Aufruf einen Weg * zu einem Vorgaengerknoten von knoten, d.h. der * Knoten ist bei Aufruf noch n i c h t in weg abgelegt. * Beim ersten Aufruf, d.h. wenn knoten der Startknoten ist, * enthaelt weglaenge den Wert 0 * * @param knoten Knoten, von dem aus ein Weg gesucht werden soll * * * @return true: Weg wurde gefunden, weg und weglaenge enthalten die Knoten des Weges, * false: es gibt keinen Weg * */ private static boolean probieren ( int knoten ) { // Diese Methode ist im Rahmen der Aufgabe zu formulieren } 4/20 private static void matrix1(){ boolean[][] m = { { true, true, false,false,false,false,false,false,false}, { false,true, true, true, false,false,false,false,false}, { false,false,true, false,false,false,false,false,false}, { false,false,false,true, true ,true, false,false,false}, { false,true, false,false,true, false,false,false,false}, { false,false,false,false,false,true, true, true, false}, { false,false,false,false,false,true, true, false,false}, { false,false,false,false,false,false,true, true, true }, { false,false,false,false,false,false,false,false,true } }; matrix = m; start = 0; ziel = 8; } public static void main(String[] args){ matrix1(); knotenzahl=matrix.length; weg = new int[knotenzahl]; weglaenge=0; // Der bisher gefundene Weg ist leer if (probieren(start)){ for (int i=0; i<weglaenge; i++) System.out.print(weg[i]+" "); System.out.println(); } else{ System.out.println( "Es gibt keinen Weg von "+start+" nach "+ziel); } } } (20 Punkte) Lösung: a.) 5/20 0 1 3 5 2 4 6 7 8 b.) private static boolean probieren ( int knoten ) { // Ueberpruefen, ob der Knoten bereits besucht wurde for(int i=0; i<weglaenge; i++) if (knoten == weg[i]) return false; // Knoten zum Weg hinzufuegen weglaenge++; weg[weglaenge-1] = knoten; if (knoten == ziel) return true; // ziel noch nicht erreicht, // d.h. alle vom Knoten direkt erreichbaren // Knoten probieren for (int i=0; i<knotenzahl; i++) { if (matrix[knoten][i]) { if (probieren(i)) return true; } } // Sackgasse, d.h. Knoten vom Weg wieder entfernen // Alle Werte und Felder haben den gleichen Zustand wie // bei Aufruf weglaenge--; return false; } Lösung 3: Heapsort Gegeben sei die Folge 37,79,11,28,90,36,21,33,99, die in einem Array vorliegt. Sortieren Sie das Array mit Heapsort. Bauen Sie dafür zunächst den Heap auf. Zeichnen Sie für 6/20 den Aufbau des Heaps geeignete Zwischenschritte und den entstandenen Heap. Zeichnen Sie anschließend den Heap und den bereits sortierten Teil des Feldes jedesmal, wenn das getauschte Element eingesunken ist. Zeichnen Sie den Heap der Übersicht halber jeweils als Binärbaum. (10 Punkte) Lösung: Ausgangsfeld als virtueller Binärbaum: 37 79 28 33 11 36 90 21 99 37 79 99 33 11 36 90 28 7/20 21 37 99 79 33 36 11 90 21 28 fertiger Anfangsheap: 99 90 79 33 36 11 37 21 28 28 eingesunken: 90 79 33 36 11 37 28 21 99 8/20 28 eingesunken: 79 37 33 36 11 28 21 90 99 90 99 21 eingesunken: 37 33 21 36 11 28 79 11 eingesunken: 9/20 36 33 21 11 28 37 79 90 99 90 99 90 99 28 eingesunken: 33 28 11 21 36 37 79 21 eingesunken: 28 21 33 11 36 37 10/20 79 11 eingesunken: 21 11 28 33 36 37 79 90 99 fertig: 11 21 28 33 36 37 Lösung 4: AVL-Bäume Gegeben sei folgender AVL-Baum: 11/20 79 90 99 18 12 9 24 15 19 13 28 22 a) Handelt es sich bei dem abgebildeten Baum um einen Heap? 25 (1 Punkt) b) Fügen Sie nacheinander die Zahlen • 17, • 14 und • 23 in diesen AVL-Baum ein und zeichnen Sie ihn nach jedem Einfügevorgang. Falls Rotationen zum Ausgleichen nötig sind, geben Sie bitte an, um welche es sich handelt! (6 Punkte) c) Löschen Sie aus dem obigen Ursprungsbaum (nicht dem erweiterten!) die Zahl 18. (3 Punkte) Lösung: a) Nein, da bei einem Heap ein Knoten immer größer als seine Söhne sein muß, das ist bei Suchbäumen im Allgemeinen nicht der Fall. b) 12/20 Einfügen 17 18 12 24 9 15 13 19 17 28 22 25 Einfügen 14 18 12 24 9 15 13 19 17 28 22 25 14 R-Rotation um 15 18 12 24 9 13 19 15 14 22 17 13/20 28 25 L-Rotation um 12 18 13 12 9 24 15 19 17 14 28 22 25 Einfügen 23 18 13 12 9 24 15 19 17 14 28 22 25 23 L-Rotation um 19 18 24 13 12 9 15 14 22 17 14/20 19 28 23 25 c) Löschen der 18 15 15 13 Lösung 5: B-Bäume Gegeben sei folgender B-Baum der Ordnung 2: 31 42 64 11 22 33 36 37 41 44 45 59 70 72 77 82 a) Fügen Sie nacheinander die Zahlen • 27, • 38 und • 80 in diesen B-Baum ein und zeichnen Sie ihn nach jedem Einfügevorgang. Verwenden Sie beim Einfügen den einfachen Algorithmus, d. h. bei einem Überlauf des Knotens soll keine Anleihe beim Nachbarknoten gemacht werden. (6 Punkte) b) Löschen Sie aus Ihrem Ergebnis nacheinander die Schlüssel • 36 • 64 und • 11. Zeichnen Sie dabei jeweils den B-Baum nach einem Löschvorgang. Hinweis: Beim Löschen in einem Nicht-Blatt wird der Inorder-Vorgänger des zu löschenden Schlüssels (d. h. der nächstkleinere Schlüssel) an diese Stelle gebracht und 15/20 an der ursprünglichen Stelle gelöscht, so dass letztendlich im Blatt – wie in der Vorlesung angegeben – gelöscht werden kann. Sollten Anleihen bei einem Nachbarn oder Verschmelzen mit einem Nachbarn nötig sein, soll zunächst der linke gewählt werden. (6 Punkte) c) Kann es sich beim oben abgebildeten Baum auch um einen B-Baum der Ordnung 3 handeln? Begründen Sie Ihre Antwort! (1 Punkt) Lösung: a) • Einfügen der 27: 31 42 64 11 22 27 33 36 37 41 44 45 59 70 72 77 82 • Einfügen der 38: (Überlauf) 31 37 42 64 11 22 27 33 36 38 41 44 45 59 70 72 77 82 • Einfügen der 80: (Doppelter Überlauf) 42 31 37 11 22 27 b) 33 36 64 77 38 41 • Löschen der 36: (Unterlauf und Anleihe links) 16/20 44 45 59 70 72 80 82 42 27 37 11 22 31 33 64 77 38 41 44 45 59 70 72 80 82 • Löschen der 64: (Ersetze 64 durch 59, lösche 59) 42 27 37 11 22 31 33 59 77 38 41 44 45 70 72 80 82 44 45 70 72 80 82 • Löschen der 11: (Doppelter Unterlauf) 37 42 59 77 22 27 31 33 38 41 c) Nein, da die B-Baum Bedingung nicht erfüllt ist: Bei Ordnung m müssen alle Knoten außer der Wurzel mindestens m Werte, dürfen aber höchstens 2 · m Werte enthalten. Das ist hier beim ersten Knoten der zweiten Reihe nicht der Fall. [Die Kriterien, dass die Blätter auf einer Stufe liegen; alle Werte in den Knoten aufsteigend geordnet sind und dass die Nachfolgerzeiger auf Knoten zeigen, die (im Fall des linken Nachfolgers) kleinere Werte beinhalten als der jeweilige Wert, von dem der Zeiger ausgeht bzw. (im Fall des rechten Nachfolgers) größere Werte, sind alle erfüllt. Aber das ist nicht gefragt, da das ja auch beim abgebildeten Baum gelten muß, hier geht es um das m − 2 · m-Kriterium.] 17/20 Lösung 6: Hashverfahren Gegeben sei die unten abgebildete Hashtabelle der Länge 11, bei der die Schlüssel mit der Hashfunktion h(k) = (2 ∗ k) MOD 11 bestimmt werden. Als Kollisionsstrategie wird interne Kollisionsbehandlung mit quadratischem Sondieren angewandt, d. h. hi (k) = (h(k) + i2 ) MOD 11 0 1 2 3 4 5 6 7 8 9 10 12 30 19 16 a) Fügen Sie die folgenden Werte in der angegebenen Reihenfolge in diese Hashtabelle ein und geben Sie dabei die Anzahl der aufgetretenen Kollisionen an: • 65 • 14 • 41 (6 Punkte) b) Was unternehmen Sie, wenn die Hashtabelle voll ist, Sie aber weitere Werte einfügen müssen? (2 Punkte) Lösung: a) h(65) = 2 ∗ 65 MOD 11 = 9 −→ ok 0 1 2 3 4 5 6 7 8 9 10 12 30 19 65 16 h(14) = 2 ∗ 14 MOD 11 = 6 −→ Kollision h1 (14) = 6 + 12 MOD 11 = 7 −→ ok; 1 Kollision 18/20 0 1 2 3 4 5 6 7 8 9 10 12 30 19 14 65 16 h(41) = 2 ∗ 41 MOD 11 = 5 −→ Kollision h1 (41) = 5 + 12 MOD 11 = 6 −→ Kollision h2 (41) = 5 + 22 MOD 11 = 9 −→ Kollision h3 (41) = 5 + 32 MOD 11 = 3 −→ ok; 3 Kollisionen 0 1 2 3 4 5 6 7 8 9 10 12 41 30 19 14 65 16 b) Die Hashtabelle muss in eine größere Hashtabelle umgeschrieben werden. Lösung 7: Topologische Sortierung a) Geben Sie eine topologische Sortierung für den folgenden gerichteten Graphen an: - 1 2 6 ? - 4 3 (5 Punkte) b) Betrachten Sie die Aussage: Die topologische Sortierung eines gerichteten Graphen ohne Zyklen ist immer eindeutig bestimmt. Beweisen Sie die Aussage oder widerlegen Sie sie durch Angabe eines Gegenbeispiels. (5 Punkte) Lösung: 19/20 a) topologische Sortierung: - 1 1 2 4 6 ? - 2 4 3 3 b) Gegenbeispiel: - 1 ? ? - 4 2 3 hat zwei verschiedene topologische Sortierungen: 1 1 - ? 3 4 2 2 1 1 ? - - ? 3 4 2 4 20/20 2 3 ? - 3 4