Sortierte Folgen 250
Sortierte Folgen: he 1,...,e n i mit e 1 apple applee n 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 apple ` < r apple n + 1 and a[`] < k apple a[r] m:= b(r + `)/2c // ` < m < r if k apple 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 apple ` < r apple n + 1 and a[`] < k apple a[r] m:= b(r + `)/2c // ` < m < r if k apple 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 apple ` < r apple n + 1 and a[`] < k apple a[r] m:= b(r + `)/2c // ` < m < r if k apple a[m] then r:= m else `:= m return r Indizes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] Einträge: [, 2, 3, 5, 7, 11, 13, 17, 19, ] [, 2, 3, 5, 7, 11, 13, 17, 19, ] [, 2, 3, 5, 7, 11, 13, 17, 19, ] [, 2, 3, 5, 7, 11, 13, 17, 19, ] 254
Dynamische Sortierte Folgen Grundoperationen insert, remove, update, locate O(log n) (M.locate(k):= min{e 2 M : e k}) 255
Mehr Operationen hmin,...,a,...,b,...,maxi min: Erstes Listenelement max: Letztes Listenelement Zeit O(1) Zeit O(1) rangesearch(a, b) result:= hi h:= locate(a) while h! e apple b do result.pushback(h! e) h:= h!next return result // O(log n + result ) Navigations Datenstruktur 2 3 5 7 11 13 17 19 00 256
Noch mehr Operationen I (re)build: Navigationsstruktur für sortierte Liste aufbauen O(n) I hw,..., xi.concat(hy,..., zi)=hw,..., x, y,..., zi O(log n) I 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: Hybrid-Datenstruktur oder log n M statische Datenstrukturen geometrisch wachsende 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 apple k über r erreichbare Blätter haben Schlüssel > k 3 7 17 13 2 5 11 19 2 3 5 7 11 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) 7 17 3 13 2 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 apple x then return x else return x!next if k apple x then return locate(k, x!left) else return locate(k, x!right) 3 7 15? < > 17 13 2 5 11 > 19 2 3 5 7 11 13 17 19 00 263
locate(k) anderesbeispiel Idee: Benutze Spaltschlüssel x als Wegweiser. Function locate(k, x) if x is a leaf then if k apple x then return x else return x!next if k apple x then return locate(k, x!left) else return locate(k, x!right) 3 7 18? < > 18 13 2 5 11 > 19 2 3 5 7 11 13 17 19 00 264
Invariante von locate(k) Function locate(k, x) if x is a leaf then if k apple x then return x else return x!next if k apple x then return locate(k, x!left) else return locate(k, x!right) <k <x x root >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 apple x then return x else return x!next if k apple x then return locate(k, x!left) else return locate(k, x!right) <k x root >k Fall k = x: return x Fall k < x: return x Fall k > x: return x!next 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 apple x then return x else return x!next if k apple x then return locate(k, x!left) else return locate(k, x!right) 2 3 5 7 15? < 11 13 2 3 5 7 11 13 17 19 > 17 > 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 u k v u insert e u u k v e T e e T T e T e e k=key(e) 268
Beispiel insert 17 insert 13 insert 11 19 19 17 19 17 13 11 13 17 19 19 00 17 19 00 13 17 19 00 11 13 17 19 00 Problem: Der Baum wird beliebig unbalanciert. langsam 269