Sortierte Folgen 250 Sortierte Folgen: he1 , . . . , en i mit e1 · · · en „kennzeichnende“ Funktion: M.locate(k):= addressof min {e 2 M : e k} Navigations−Datenstruktur 2 3 5 7 11 13 17 19 00 Annahme: Dummy-Element mit Schlüssel • Achtung: In Abbildungen sieht • wie 00 aus 251 Statisch: Sortiertes Feld mit binärer Suche // Find min {i 2 1..n + 1 : a[i] k} Function locate(a[1..n], k : Element) (`, r ):= (0, n + 1) // Assume a[0] = •, a[n + 1] = • while ` + 1 < r do invariant 0 ` < r n + 1 and a[`] < k a[r ] m:= b(r + `)/2c // ` < m < r if k a[m] then r := m else `:= m return r Übung: Müssen die Sentinels • / • tatsächlich vorhanden sein? Übung: Variante von binärer Suche: bestimme `, r so dass a[`..r 1] = [k, . . . , k], a[` 1] < k und a[r ] > k 252 Statisch: Sortiertes Feld mit binärer Suche // Find min {i 2 1..n + 1 : a[i] k} Function locate(a[1..n], k : Element) (`, r ):= (0, n + 1) // Assume a[0] = •, a[n + 1] = • while ` + 1 < r do invariant 0 ` < r n + 1 and a[`] < k a[r ] m:= b(r + `)/2c // ` < m < r if k a[m] then r := m else `:= m return r Zeit: O(log n) Beweisidee: r ` „halbiert“ sich in jedem Schritt 253 Binäre Suche – Beispiel: k = 15 Function locate(a[1..n], k : Element) // min {i 2 1..n + 1 : a[i] k} (`, r ):= (0, n + 1) // Assume a[0] = •, a[n + 1] = • while ` + 1 < r do invariant 0 ` < r n + 1 and a[`] < k a[r ] m:= b(r + `)/2c // ` < m < r if k a[m] then r := m else `:= m return r Indizes: Einträge: [ [ [ [ [0, •, •, •, •, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 5, 5, 5, 5, 4, 7, 7, 7, 7, 5, 11, 11, 11, 11, 6, 13, 13, 13, 13, 7, 17, 17, 17, 17, 8, 19, 19, 19, 19, 9] •] •] •] •] 254 Dynamische Sortierte Folgen – Grundoperationen insert, remove, update, locate (M.locate(k):= min {e 2 M : e O(log n) k}) 255 Mehr Operationen hmin, . . . , a, . . . , b, . . . , maxi min: Erstes Listenelement Zeit O(1) max: Letztes Listenelement Zeit O(1) rangeSearch(a, b) result:= hi h:= locate(a) while h ! e b do result.pushBack(h ! e) h:= h !next return result 2 // O(log n + |result|) Navigations−Datenstruktur 3 5 7 11 13 17 19 00 256 Noch mehr Operationen I I I (re)build: Navigationsstruktur für sortierte Liste aufbauen O(n) hw , . . . , xi.concat(hy , . . . , zi) = hw , . . . , x, y , . . . , zi O(log n) hw , . . . , x, y , . . . , zi.split(y ) = (hw , . . . , xi, hy , . . . , zi) O(log n) Zählen: rank, select, rangeSize O(log n) Fingersuche: = Abstand zu Fingerinfo zusätzlicher Parameter für insert, remove, locate,. . . O(log n) ! log Navigations−Datenstruktur 2 3 5 7 11 13 17 19 00 257 Abgrenzung Hash-Tabelle: nur insert, remove, find. Kein locate, rangeQuery Sortiertes Feld: nur bulk-Updates. Aber: n Hybrid-Datenstruktur oder log M geometrisch wachsende statische Datenstrukturen Prioritätsliste: nur insert, deleteMin, (decreaseKey, remove). Dafür: schnelles merge Sortierte Folgen allgemein: die eierlegende Wollmilchdatenstruktur. „Etwas“ langsamer als speziellere Datenstrukturen 258 Sortierte Folgen – Anwendungen I Best-First Heuristiken I Alg. Geometrie: Sweepline-Datenstrukturen I Datenbankindex I ... 259 Anwendungsbeispiel: Best Fit Bin Packing Procedure binPacking(s) B : SortedSequence // used bins sorted by free capacity foreach e 2 s by decreasing element size // sort if ¬9b 2 B : free(b) e then B.insert(new bin) locate b 2 B with smallest free(b) e insert e into bin b Zeit: O(|s| log |s|) Qualität: „gut“. Details: nicht hier 260 Binäre Suchbäume Blätter: Elemente einer sortierten Folge. Innere Knoten v = (k, `, r ), (Spalt-Schlüssel, linker Teilbaum, rechter Teilbaum). Invariante: über ` erreichbare Blätter haben Schlüssel k über r erreichbare Blätter haben Schlüssel > k 17 7 3 13 2 2 5 3 5 11 7 11 19 13 17 19 00 261 Varianten, Bemerkungen I Dummy-Element im Prinzip verzichtbar I Oft speichern auch innere Knoten Elemente I „Suchbaum“ wird oft als Synomym für „sortierte Folge“ verwendet. (Aber das vermischt (eine) Implementierung mit der Schnittstelle) 17 7 3 2 13 5 11 19 262 locate(k) Idee: Benutze Spaltschlüssel x als Wegweiser. Function locate(k, x) if x is a leaf then if k x then return x else return x !next if k x then return locate(k, x !left) else return locate(k, x !right) 15? < 7 17 > 3 13 2 2 5 3 5 11 7 11 > 13 17 19 19 00 263 locate(k) – anderes Beispiel Idee: Benutze Spaltschlüssel x als Wegweiser. Function locate(k, x) if x is a leaf then if k x then return x else return x !next if k x then return locate(k, x !left) else return locate(k, x !right) 18? < 7 18 > 3 13 2 2 5 3 5 11 7 11 > 13 17 19 19 00 264 Invariante von locate(k) Function locate(k, x) if x is a leaf then if k x then return x else return x !next if k x then return locate(k, x !left) else return locate(k, x !right) root x <k <x >x >k Invariante: Sei X die Menge aller von x erreichbaren Listenelemente. Listenelemente links von X sind < k Listenelemente rechts von X sind > k 265 Ergebnisberechnung von locate(k) Function locate(k, x) if x is a leaf then if k x then return x else return x !next if k x then return locate(k, x !left) else return locate(k, x !right) Fall k = x: return x Fall k < x: return x Fall k > x: return x !next root x <k >k Bingo! links ist es auch nicht nächstes ist > k und k gibt es nicht 266 Laufzeit von locate(k) Function locate(k, x) if x is a leaf then if k x then return x else return x !next if k x then return locate(k, x !left) else return locate(k, x !right) 15? < 7 17 > 3 13 2 2 5 3 5 11 7 11 > 13 17 19 19 00 Laufzeit: O(Höhe). Bester Fall: perfekt balanciert, d. h. Tiefe = blog nc Schlechtester Fall: Höhe n 267 Naives Einfügen Zunächst wie locate(e). Sei e 0 gefundenes Element, u der Elterknoten insert e v u k e’ T e u e’ T T k=key(e) insert e u e’ u k T e v e’ 268 Beispiel insert 17 insert 13 insert 11 19 19 19 19 19 17 17 00 17 17 13 13 19 00 13 11 17 19 00 11 13 17 19 00 Problem: Der Baum wird beliebig unbalanciert. langsam 269