Grundzüge von Datenstrukturen und Algorithmen (WS 2013/2014) Lösungsvorschlag zu Aufgabenblatt 5 Aufgabe 1 Idee Wir nutzen, dass das Feld geordnet ist, indem wir ausgehend von der vermuteten Stelle f in die richtige Richtung mit sich verdoppelnden Schrittweiten suchen, um das Intervall, indem das Element liegen muss, einzugrenzen. Dann benötigen wir nur noch eine binr̈e Suche. Algorithmus finde(A, x, wenn A[f] wenn A[f] wenn A[f] f) = x dann gib wahr zurueck < x dann suche_rechts(A, x, f, 1) > x dann suche_links(A, x, f, 1) suche_rechts(A,x,f,schritt) //wir wissen: A[f] < x i <- min(f + schritt, A.letzterIndex) wenn A[i] = x dann gib wahr zurueck wenn A[i] > x dann gib das Ergebnis der binaere Suche nach x in A[f..i] zurueck wenn A[i] < x und i < A.letzterIndex dann gib das Ergebnis von suche_rechts(A,x,i, schritt * 2) zurueck ansonsten gib falsch zurueck suche_links(A,x,f,schritt) //wir wissen: A[f] > x i <- max(f - schritt, 1) wenn A[i] = x dann gib wahr zurueck wenn A[i] < x dann gib das Ergebnis der binaere Suche nach x in A[i..f] zurueck wenn A[i] > x und i > 1 dann gib das Ergebnis von suche_links(A,x,i, schritt * 2) zurueck sonst gib falsch zurueck Korrektheit a) (x ∈ A) Im trivialen Fall ist A[f ] = x und finde(A, x, f) gibt wahr zurück. Wir betrachten nun den Fall, dass A[f ] < x und wir suche_rechts() ausführen (der andere Fall ergibt sich analog): Es gilt A[f ] < x, da suche_rechts() immer nur dann aufgerufen wird, wenn diese Bedingung eintritt. Es wird ein neues Element A[i] geprüft, dass eine gewisse Entfernung nach rechts vom aktuellen f hat. Ist dieses das gewünschte x, geben wir korrekterweise wahr zurück. Gilt dagegen A[i] > x, so ist A[f ] ≤ x ≤ A[i] und damit muss das z mit A[z] = x zwischen f und i 1 Grundzüge von Datenstrukturen und Algorithmen (WS 2013/2014) Lösungsvorschlag zu Aufgabenblatt 5 liegen. Führen wir eine binäre Suche in diesem Bereich durch, so finden wir x und geben wahr zurück. Ist dagegen A[i] < x, so müssen wir weiter nach rechts suchen und werden x finden, da spätestens wenn i = n der Fall A[i] ≤ x eintritt, der wie gezeigt korrekt behandelt wird. b) (x ∈ / A) Wenn x kein Element von A ist, so können drei Fälle eintreten. Im ersten sind alle Elemente in A kleiner als x. In diesem Fall wird suche_rechts() solange ausgeführt, bis i = n und kein rekursiver Aufruf mehr erfolgt und es wird falsch zurückgegeben. Analog gibt suche_links() falsch zurück, wenn i = 1 für den Fall, dass x kleiner ist als alle Elemente in A. Im letzten Fall wird wie besprochen ein Intervall gefunden, in dem x liegen muss. Hat die binäre Suche in diesem Intervall keinen Erfolg, so ist dieses Element nicht in A enthalten; es wird falsch zurückgegeben. Laufzeit a) Gilt für die tatsächliche Position z von x, dass z = x ± ∆, so benötigen wir einen Vergleich, wenn ∆ = 0. Ansonsten sind höchstens (log ∆) + 1 Schritte nötig, um das Intervall einzugrenzen, da die Entfernung von der vermuteten Stelle in jedem Schritt mehr als verdoppelt wird. Das Intervall hat maximal eine Größe von ∆, denn spätestens sobald die Schrittweite so groß ist, muss x in diesem neuen Bereich liegen, da bereits f ± schrittweite = z gilt. Damit ergibt sich eine Laufzeit von O((log ∆) + 1 + log ∆) = O((log ∆) + 1). b) Ist x ∈ / A, so definiert sich das ∆ als Abstand von der vermuteten Stelle zur Position des nächsten Elements, das größer (falls A[f ] < x) bzw. kleiner (wenn A[f ] > x) als x ist. Ist x größer als jedes andere Element, so ist dies n − f . Ist x kleiner als alle Elemente in A, dann ist ∆ = f − 1. ∆ ist also der Abstand zu der Position, an der x stehen würde, wenn es enthalten wäre. Aufgabe 2 • Erinnerung: Der Nachfolger eines Knoten x ist der Knoten mit dem kleinsten Schlüssel der größer als xs Schlüssel ist. • Aufgrund der Eigenschaft binärer Suchbäume ist der Nachfolger y von x im rechten Teilbaum von x (alle Schlüssel im linken Teilbaum sind kleiner als der von x) • Da es keinen Schlüssel zwischen x und y gibt (sonst wäre y nicht der Nachfolger), gibt es keinen Knoten in diesem Teilbaum, der kleiner als y ist • Daher hat y einen leeren linken Teilbaum =⇒ y hat wenn überhaupt nur 1 Kind (falls der rechte Teilbaum vorhanden ist) 2 Grundzüge von Datenstrukturen und Algorithmen (WS 2013/2014) Lösungsvorschlag zu Aufgabenblatt 5 Aufgabe 3 Für “Höhe eines Baumes” benutzen wir im Folgended die Definition “Höhe ist Anzahl Kanten des Längsten Pfades”. Für die Definition mit “Knoten” anstatt Kanten ändern sich die Zahlen nur etwas, der Beweis bleibt der gleiche. Maximale Höhe Der degenerierte binäre Suchbaum, bei dem jeder Knoten außer dem (einen) Blatt nur ein Kind hat, hat Höhe n − 1. Er ensteht etwa, wenn n Knoten in aufsteigender Reihenfolge eingefügt werden, da dann immer im rechten Teilbaum eingefügt wird. Damit ein Suchbaum Höhe h haben kann, muss es mindestens einen Pfad dieser Länge geben. Ein Pfad der Höhe h hat h + 1 Knoten. Somit kann es keinen Suchbaum mit Höhe ≥ n geben, da sonst der “verursachende” Pfad > n Knoten hätte. Somit ist die Höhe n − 1 maximal. Minimale Höhe Ein voller binärer Suchbaum der Tiefe h hat 2h − 1 Knoten (inklusive Blätter). Für einen vollen binären Suchbaum mit n Knoten gilt also: 2h − 1 = n ⇐⇒ h = log2 (n + 1) Ein balancierter Baum, dessen Pfadlängen sich maximal um 1 unterscheiden, hat > 2h−1 − 1 und ≤ 2h − 1 Blätter. Für einen balancierten Baum mit n Knoten gilt also: ⇐⇒ ⇐⇒ 2h−1 − 1 < n ≤ 2h − 1 h−1 2 < n+1 ≤ 2h h−1 < log2 (n + 1) ≤ h Eine geringere Höhe kann nicht erreicht werden, da dann eine dichtere Packung als beim vollen binären Suchbaum gefunden wäre. 3