3.3 Optimale binäre Suchbäume Problem 3.3.1. Sei S eine Menge von Schlüsseln aus einem endlichen, linear geordneten Universum U, S = {a 1,,...,a n } U und S = n N. Wir wollen S in einem binären Suchbaum abspeichern, um Anfragen der Form a S? für beliebige Elemente a U zu beantworten. Der binäre Suchbaum enthalte in den inneren Knoten die Schlüssel aus S. Entsprechend einem binären Suchbaum gelte, dass alle Elemente im linken Teilbaum eines inneren Knoten kleiner oder gleich dem Schlüssel im inneren Knoten sind. Die Blätter sollen die Intervalle zwischen den Schlüsseln in S enthalten, von links nach rechts aufsteigend sortiert: (,a 1 ),(a 1, ),...,(a,a n ),(a n, ). Die Blätter können unterschiedliche Höhen haben. Die Zugriffswahrscheinlichkeiten seien: 1. p i := Wahrscheinlichkeit, dass bei einer Suchanfrage nach a i S gefragt wird. 2. q i := Wahrscheinlichkeit, dass bei einer Suchanfrage nach a / S gefragt wird, mit a i < a < a i+1. 3. q 0 := Wahrscheinlichkeit, dass nach a < a 1 gefragt wird. 4. q n := Wahrscheinlichkeit, dass nach a > a n gefragt wird. wobei n i=1 p i + q i = 1, da es sich um eine Wahrscheinlichkeitsverteilung handelt. Frage 3.3.2. Wie sieht der optimale binäre Suchbaum für S aus? Definition 3.3.3. Ein binärer Suchbaum ist optimal, wenn die erwartete Anzahl an Vergleichen für eine Suchanfrage minimal ist. Wir minimieren folgende Zielfunkunktion: P = n n p i (Tiefe(i) + 1) + q j (Tiefe (j)) i=1 1. j=0 2. wobei Tiefe(i) die Tiefe des Knotens a i sei und Tiefe (j) die Tiefe des Blattes (a j,a j+1 ) für 0 < j < n und Tiefe (0) die Tiefe des Blattes (,a 1 ) bzw. Tiefe (n) die Tiefe des Blattes (a n, ). Also ist 1. Summe des Produktes aus der Anfragewahrscheinlichkeit eines Schlüssels a i S und der Länge dessen Suchpfades + 1 (für die Wurzel). 2. Summe über die Produkte aus allen möglichen Anfragen von Schlüsseln a S und der Länge deren Suchpfade. 63
3.3.1 Beispiel Wir betrachten folgendes Beispiel. Sei U = {1,2,3,4,5,6,7} und die Menge der Schlüssel S = {2, 5, 6}. Nach Schlüsseln aus S wird mit den Wahrscheinlichkeiten p 1 = 0,3, p 2 = 0,2 und p 3 = gefragt. Die Intervalle zwischen den Schlüsseln in S seien gleich wahrscheinlich, d.h. q 0 = q 1 = q 2 = q 3 =. Dann sind z.b. die Suchbäume in Abbildung 3.26 möglich. p = 0,2 2 p 1 = 0,3 a 1 a 3 p = (_,a 1 ) (a 1,) (,a 3 ) (a 3,_) 3 (a) Baum T 1 mit P T1 = 1, 8 p 1 = 0,3 a 1 p = 0,2 2 (_,a 1 ) (a 1,a2) a 3 (a,a ) 2 3 p = 3 (a 3,_) (_,a ) 1 p 1 = 0,3 a 1 (a 1,a2) p 2 = 0,2 (a,a ) 2 3 a 3 p = 3 (a,_) 3 (b) Baum T 2 mit P T2 = 2, 3 (c) Baum T 3 mit P T3 = 1, 9 Abbildung 3.26: Beispiele für binäre Suchbäume Die Zielfunktion für die Suchbäume T 1,T 2,T 3 in Abbildung 3.26 beträgt: P T1 = ( + + 0,3) + ( + + ) + (( + + 0,3) + ( + + ) + 0,2) = (0,5 + 0,3) + ((0,5 + 0,3) + 0,2) = 1,8. P T2 = ( + + 0,3) + (0,5 + + 0,2) + (0,8 + + ) = 0,5 + 0,8 + 1,0 = 2,3. P T3 = ( + + ) + ( + 0,3 + 0,2) + ( + 0,6 + 0,3) = 0,3 + 0,6 + 1,0 = 1,9. In diesem Beispiel ist also der Suchbaum T 1 besser als die Bäume T 2 und T 3. 64
3.3.2 Algorithmus Gesucht ist ein Algorithmus, der für eine gegebene Schlüsselmenge S aus einem Universum U einen optimalen binären Suchbaum konstruiert. Bemerkung. Die Methode des Durchtestens aller möglichen Suchbäume (brute force) ist zwar möglich aber ineffizient, da es ( ) 2n 1 n n + 1 4n zu untersuchende Bäume gibt. Für große n ist diese Methode daher praktisch nicht umsetzbar. Wir stellen zunächst einige Vorüberlegungen an. Dazu benutzen wir folgende Bezeichnungen, welche in Abbildung 3.27 schematisch dargestellt sind. Sei S eine Teilmenge von S: S S, S = {a i,...,a j }. T i,j sei der optimale Suchbaum für S. Die Wurzel von T i,j sei a m, m {i,...,j}. Die inneren Knoten von T i,j sind {a i,...,a j }. Die Blätter von T i,j haben die Gestalt (a i 1,a i ),(a i,a i+1 ),...,(a j 1,a j ),(a j,a j+1 ) Mit P Ti,j bezeichnen wir die Zielfunktion eingeschränkt auf den Teilbaum T i,j. Die Zugriffswahrscheinlichkeiten im Teilbaum T i,j sind p i = pi und q i = q i, wobei die Wahrscheinlichkeit dafür sei, dass nach einem Element a [a i,a j ] gesucht wird. Behauptung 3.3.4. Die erwartete Anzahl an Vergleichen für eine Suchanfrage über einem Teilbaum T i,j ist im Mittel: Beweisskizze. Herleitung über: P Ti,j = 1 + w i,m 1 P Tl + w m+1,j P Tr. P Ti,j = I := II := p k (Tiefe(k) + 1) + k=i I m 1 k=i m 1 k=i 1 k=i 1... + p m (Tiefe(m) + 1) +... + q m (Tiefe (m)) + q k (Tiefe (k)) II... k=m+1 k=m+1... 65
w i,m-1 a m w m+1,j T T i,j T l T r 1 n p i p m p j i m-1 m+1 j Abbildung 3.27: Schematische Darstellung der Ausgangssituation. Lemma 3.3.5. Der binäre Suchbaum T i,j sei optimal für die Menge {a i,...,a j } und sei a m die Wurzel von T i,j. Ferner sei T l linker Teilbaum von a m und T r rechter Teilbaum von a m. Dann ist T l bzw. T r optimaler binärer Suchbaum für die Menge {a i,...,a m 1 } bzw. {a m+1,...,a j }. Beweis. Angenommen es gibt T l mit P T l < P T l P T i,j = 1 + w i,m 1 P T l + w m+1,j P Tr < 1 + w i,m 1 P Tl + w m+1,j P Tr = P Ti,j. Dies steht jedoch im Widerspruch dazu, dass T i,j optimal ist. Seien folgende Variablen für den Algorithmus vereinbart: r i,j := Index der Wurzel für T i,j c i,j := Kosten von T i,j = P Ti,j := Wahrscheinlichkeit, dass a [a i,a j ] (wie bisher). Behauptung 3.3.6. Es gilt c i,j = P Ti,j = + c i,m 1 + c m+1,j = w i,m 1 + p m + w m+1,j. 66
Basierend auf den vorangegangenen Lösungen, können wir nun einen Algorithmus zum Berechnen des optimalen binären Suchbaums angeben. Algorithm 3: [Bellman, 1957] Iterative Suche nach dem optimalen Suchbaum T. 1: for i = 0,...,n do 2: w i+1,i = q i 3: c i+1,i = 0 4: end for 5: for k = 0,...,n 1 do 6: for i = 1,...,n k do 7: j = i + k 8: Bestimme m mit i m j, so dass c i,m 1 + c m+1,j minimal ist. 9: r i,j = m 10: = w i,m 1 + w m+1,j + p m 11: c i,j = c i,m 1 + c m+1,j + 12: end for 13: end for Der Algorithmus benutzt das Konzept der dynamischen Programmierung. Bei dynamischer Programmierung wird die Lösung eines Problems durch Zusammenfügen der Lösungen von Teilproblemen erreicht. Die Lösungen der Teilprobleme sind dabei voneinander abhängig. Insbesondere beruht die Lösung eines Teilproblems auf den Lösungen von kleineren Teilproblemen. Bei dynamischer Programmierungen werden diese kleineren Teilprobleme nur einmal gelöst, und ihre Lösung für mehrere größere, sie enthaltene Teilprobleme weiterverwendet. Eine ausführlichere Beschreibung von dynamischer Programmierung findet sich z.b. im Kapitel 16 des Buches Introduction to Algorithms von Cormen et.al. In unserem Fall sind die Teilprobleme gegeben durch die Teilgraphen T i,j,1 i j n. Der Algorithmus berechnet nacheinander die optimalen Lösungen für die Teilgraphen T i,j für k = i j = 0,...,n 1. Für k = 0 berechnet er die optimalen Lösungen für die Teilgraphen T i,i,i = 1,...,n, welche nur aus einem Knoten, a i, bestehen. Für k > 0 berechnet er die optimale Lösung für T i,j aufbauend auf den bereits berechneten kleineren Lösungen. Im letzten Schritt wird so der optimale binäre Suchbaum T 1,n = T berechnet. 3.3.3 Beispiel Wir veranschaulichen die Arbeitsweise des Algorithmus an folgendem Beispiel. Gegeben sei die Menge S = {a 1,,a 3,a 4 }. Nach den Schlüsseln in S wird mit den Wahrscheinlichkeiten p 1 = p 2 =, p 3 = 0,2 und p 4 = 0,2 gefragt. Die von den Schlüsseln gebildeten Intervalle seien auch hier gleich wahrscheinlich, d.h. q 0 = q 1 = q 2 = q 3 = q 4 =. Die vom Algorithmus iterativ berechneten Ergebnisse für die Teilprobleme lassen sich in folgender Tabelle 3.1 abspeichern und darstellen. In der ersten Blockzeile der Tabelle stehen die während der Initialisierung berechneten Werte und in den folgenden Blockzeilen die Werte für wachsende k von 0 bis n 1. Den resultierenden optimalen Suchbaum, dargestellt in Abbildung 3.28, liest 67
i 0 1 2 3 4 Init w 1,0 = 0 w 2,1 = w 3,2 = w 4,3 = w 5,4 = c 1,0 = 0 c 2,1 = 0 c 3,2 = 0 c 4,3 = 0 c 5,4 = 0 k = 0 r 1,1 = 1 r 2,2 = 2 r 3,3 = 3 r 4,4 = 4 w 1,1 = 0,2 w 2,2 = 0,3 w 3,3 = 0,4 w 4,4 = 0,4 c 1,1 = 0,2 c 2,2 = 0,3 c 3,3 = 0,4 c 4,4 = 0,4 k = 1 r 1,2 = 2 r 2,3 = 3 r 3,4 = 3 w 1,2 = 0,4 w 2,3 = 0,6 w 3,4 = 0,7 c 1,2 = 0,6 c 2,3 = 0,9 c 3,4 = 1,1 k = 2 r 1,3 = 2 r 2,4 = 3 w 1,3 = 0,7 w 2,4 = 0,9 c 1,3 = 1,3 c 2,4 = 1,6 k = 3 r 1,4 = 3 w 1,4 = 2 c 1,4 = 1 Tabelle 3.1: Tabelle zur Speicherung der Berechnungen des Algorithmus man, wie in der Tabelle angedeutet, heraus. Der Index der Wurzel ist der Index m w = r 1,n im untersten Block. Die Indezes des linken und rechten Kindes der Wurzel sind m l = r 1,mw 1 und m r = r mw+1,n usw. 3.3.4 Analyse Speicherkomplexität Der Algorithmus benötigt zum Speichern der Zwischenergebnisse eine Matrix M M(n + 1 n, R). Der Speicherbedarf liegt daher bei S(n) = n (n + 1) = n 2 + n Θ(n 2 ). Laufzeitkomplexität T(n) = c 1 n + Zeile (1) bis (4) n k = c 1 n + k=0 i=1 c 2 n k k=0 i=1 Zeile (7) (c 2 + c 4 c 5 ) + k c 3 =k {}}{ +( j i)c 3 Zeile (8) = c 1 n + ((n k)c 5 + (n k)k c 3 ) k=0 = c 1 n + c 5 k + c 3 k=0 O ( n + n 2 + n 3) = O(n 3 ) k=0 k 2 + c 4 Zeile (9) bis (11) 68
i = 0 i = 1 i = 2 i = 3 i = 4 k = 0 k = 1 r 1,1 = 1 w 1,1 = 0,2 c 1,1 = 0,2 r 1,2 = 2 w 1,2 = 0,4 r 1,2 = 0,6 r 4,4 = 4 w 4,4 = 0,4 c 4,4 = 0,4 a 1 a 3 a 4 k = 2 k = 3 r 1,4 = 3 w 1,4 = 2 c 1,4 = 1 Abbildung 3.28: Resultierender Optimaler Binärer Suchbaum. 3.3.5 Optimierungen Es wurde gezeigt, dass der Iterationsalgorithmus nach Bellman kubische Laufzeit hat. Der quadratische Anteil folgt direkt aus der Anwendung der dynamischen Programmierung, so dass hier kein Ansatz zur Verbesserung gefunden werden kann. Interessant ist vielmehr Zeile (8) des Algorithmus, die den Index der Wurzel a m des optimalen Suchbaumes T i,j berechnet. Es ist in diesem Schritt nicht notwendig, alle m mit i m j zu prüfen. Sondern man kann zeigen, dass die optimalen Wurzeln von Teilbäumen, die sich nur um einen Knoten unterscheiden, relativ nahe beieinander. Dies geschieht in folgendem Lemma. Lemma 3.3.7. r i,j 1 r i,j r i+1,j. Der Beweis von Lemma 3.3.7 kann dem Buch von Donald E. Knuth The Art of Functional Programming, Band 3: Sorting and Searching entnommen werden. Durch die Eingrenzung der Wurzelsuche auf das im Lemma beschriebene Intervall reduziert sich die Gesamtlaufzeit des Algorithmus auf T(n) O(n 2 ). 69