Stacks Synonyme: Stapel, Keller, LIFO-Liste usw. Stack kann als spezielle Liste aufgefaßt werden, bei der alle Einfügungen und Löschungen an einem Ende, TOP genannt, vorgenommen werden Stack-Operationen: - CREATE: Erzeugt den leeren Stack. - INIT(S): Initialisiert S als leeren Stack. - PUSH(S, x): Fügt das Element x als oberstes Element von S ein. - POP(S): Löschen des Elementes, das als letztes in den Stack S eingefügt wurde. - TOP(S): Abfragen des Elementes, das als letztes in den Stack S eingefügt wurde. - EMPTY(S): Abfragen, ob der Stack leer ist. G.Heyer 1 Algorithmen und Datenstrukturen Schlangen Synonyme: FIFO-Schlange, Warteschlange, Queue Spezielle Liste, bei der die Elemente an einem Ende (hinten) eingefügt und am anderen Ende (vorne) entfernt werden Operationen: - CREATE: Erzeugt die leere Schlange - INIT(Q): Initialisiert Q als leere Schlange - ENQUEUE(Q, x) : Fügt das Element x am Ende der Schlange Q ein - DEQUEUE(Q): Löschen des Elementes, das am längsten in der Schlange verweilt (erstes Element) - FRONT(Q): Abfragen des ersten Elementes in der Schlange - EMPTY(Q): Abfragen, ob die Schlange leer ist G.Heyer 2 Algorithmen und Datenstrukturen Vorrangwarteschlangen Vorrangwarteschlange (priority queue) - jedes Element erhält Priorität - entfernt wird stets Element mit der höchsten Priorität (Aufgabe des FIFO-Verhaltens einfacher Warteschlangen) Operationen: - CREATE: Erzeugt die leere Schlange - INIT(P): Initialisiert P als leere Schlange - INSERT(P, x): Fügt neues Element x in Schlange P ein - DELETE(P): Löschen des Elementes mit der höchsten Priorität aus P - MIN(P): Abfragen des Elementes mit der höchsten Priorität - EMPTY(P): Abfragen, ob Schlange P leer ist. G.Heyer 3 Algorithmen und Datenstrukturen Sequentielle Suche Suche nach Element mit Schlüsselwert K Falls nicht bekannt, ob die Elemente der Liste nach ihren Schlüsselwerten sortiert sind, besteht nur die Möglichkeit, die Liste sequentiell zu durchlaufen und elementeweise zu überprüfen (sequentielle Suche) pos := 1; WHILE (pos <= L.Laenge) AND (L.Inhalt [pos].Key <> K) DO INC (pos) END; gefunden := (pos <= L.Laenge); G.Heyer 4 Algorithmen und Datenstrukturen Kosten • Erfolglose Suche erfordert n Schleifendurchläufe • erfolgreiche Suche verlangt im ungünstigsten Fall n -1 Schleifendurchläufe ( und n Schlüsselvergleiche) • mittlere Anzahl von Schleifendurchläufen bei erfolgreicher Suche: 1 n-1 n-1 Cavg (n) = i = n i=0 2 G.Heyer 5 Algorithmen und Datenstrukturen Binäre Suche Auf sortierten Listen können Suchvorgänge effizienter durchgeführt werden Sequentielle Suche auf sortierten Listen bringt nur geringe Verbesserungen (für erfolglose Suche, durchschnittlich N/2 Vergleiche) Binärsuche wesentlich effizienter durch den Einsatz der Divide-and-conquer-Strategie. Suche nach Schlüssel K in Liste mit aufsteigend sortierten Schlüsseln: G.Heyer 6 Algorithmen und Datenstrukturen 1. Falls Liste leer ist, endet die Suche erfolglos. Sonst: Betrachte Element Inhalt[m] an mittlerer Position m. 2. Falls K = Inhalt[m].Key dann ist das gesuchte Element gefunden . 3. Falls K < Inhalt[m].Key, dann durchsuche die linke Teilliste von Position 1 bis m-1 nach demselben Verfahren. 4. Sonst (K > Inhalt[m].Key) durchsuche die rechte Teilliste von Position m + 1 bis Listenende nach demselben Verfahren. G.Heyer 7 Algorithmen und Datenstrukturen Binäre Suche (2) Iterative Lösung int binsearch(int v) { int l=1; int r= N; int x; while (r>=1) { x = (l+r)/2; if (v < a[x].key) r = x-1; else l = x+1; if (v == a[x].key) return a[x].data; } return -1 } G.Heyer 8 Algorithmen und Datenstrukturen Kosten Cmin ( n ) = 1 Cmax ( n ) = [ log2 (n+1)] Cavg ( n ) log2 (n+1) -1, für große n G.Heyer 9 Algorithmen und Datenstrukturen Fibonacci-Suche Ähnlich der Binärsuche, jedoch wird Suchbereich entsprechend der Folge der Fibonacci-Zahlen geteilt. Definition der Fibonacci-Zahlen F0 = 0 F1 = 1 Fk = F k-1 + F k-2 für k >= 2. Teilung einer Liste mit n = Fk-1 sortierten Elementen: 1 i n F k-2 -1 F k-1 -1 F k- 1 G.Heyer 10 Algorithmen und Datenstrukturen - Element an der Position i = F k-2 wird mit dem Schlüssel K verglichen - Wird Gleichheit festgestellt, endet die Suche erfolgreich. - Ist K größer, wird der rechte Bereich mit F k-1 -1 Elementen, ansonsten der linke Bereich mit F k-2 -1 Elementen auf dieselbe Weise durchsucht. Kosten - für n = F k -1 sind im schlechtesten Fall k-2 Suchschritte notwendig, d. h. O ( k ) Schlüsselvergleiche - Da gilt F k c + 1.618 k , folgt C max ( n ) = O ( log 1.618 ( n+1 ) ) = O ( log2 n) . G.Heyer 11 Algorithmen und Datenstrukturen Sprungsuche Prinzip - Zunächst wird der sortierte Datenbestand in Sprüngen überquert, um den Abschnitt zu lokalisieren, der ggf. den gesuchten Schlüssel enthält, - danach wird der Schlüssel im gefundenen Abschnitt nach irgendeinem Verfahren gesucht. ... ... L 1 G.Heyer ... m ... 2m 12 ... 3m n Algorithmen und Datenstrukturen Einfache Sprungsuche - konstante Sprünge zu Positionen m, 2 m, 3 m, ... - Sobald K <= Inhalt[i].Key mit i = j * m (j = 1, 2, ...), wird im Abschnitt Inhalt[(j-1)m+1] bis Inhalt[j*m] sequentiell nach dem Suchschlüssel K gesucht. Mittlere Suchkosten ein Sprung koste a ; ein sequentieller Vergleich b Einheiten n Cavg (n) = a *m + b ( m -1 ) G.Heyer 13 Algorithmen und Datenstrukturen Optimale Sprungweite m=V(a/b)n bzw. m = V n falls a = b C avg ( n ) = a V n - a / 2 Komplexität O (V n ) G.Heyer 14 Algorithmen und Datenstrukturen Sprungsuche (2) Zwei-Ebenen-Sprungsuche - statt sequentieller Suche im lokalisierten Abschnitt wird wiederum eine Quadratwurzel-Sprungsuche angewendet, bevor dann sequentiell gesucht wird - Mittlere Kosten: Cavg ( n ) <= * a * V n + * b * n + * c * n a Kosten eines Sprungs auf der ersten Ebene; b Kosten eines Sprungs auf der zweiten Ebene; c Kosten für einen sequentiellen Vergleich - Für a = b = c ergibt sich: Cavg ( n ) <= a G.Heyer 15 Vn+n Algorithmen und Datenstrukturen Verbesserung durch optimale Abstimmung der Sprungweiten m1 und m2 der beiden Ebenen - Mit a = b = c ergeben sich als optimale Sprungweiten m1 = n und m2 = n - mittlere Suchkosten: C avg ( n ) = 3/2* a * n Verallgemeinerung zu n-Ebenen-Verfahren ergibt ähnlich günstige Kosten wie Binärsuche (Übereinstimmung bei log2n Ebenen) Sprungsuche vorteilhaft, wenn Binärsuche nicht anwendbar ist (z. B. bei blockweisem Einlesen der sortierten Sätze vom Externspeicher) G.Heyer 16 Algorithmen und Datenstrukturen Exponentielle Suche Anwendung wenn Länge des sortierten Suchbereichs zunächst unbekannt bzw. sehr groß ist. Vorgehensweise - für Suchschlüssel K wird zunächst obere Grenze für den zu durchsuchenden Abschnitt bestimmt i := 1; WHILE K > L.Inhalt [i].Key DO i := i + i; END; - Für i > 1 gilt für den auf diese Weise bestimmten Suchabschnitt L.Inhalt [i DIV 2].Key < K <= L.Inhalt [i].Key - Suche innerhalb des Abschnitts mit irgendeinem Verfahren G.Heyer 17 Algorithmen und Datenstrukturen Sind in der sortierten Liste nur positive, ganzzahlige Schlüssel ohne Duplikate gespeichert, wachsen Schlüsselwerte mindestens so stark wie die Indizes der Elemente. - i wird höchstens log2 K mal verdoppelt - Bestimmung des gesuchten Intervalls erfordert maximal log2 K Schlüsselvergleiche - Suche innerhalb des Abschnitts (z. B. mit Binärsuche ) erfordert auch höchstens log2 K Schlüsselvergleiche Gesamtaufwand O ( log2 K ) G.Heyer 18 Algorithmen und Datenstrukturen Interpolationssuche Schnellere Lokalisierung des Suchbereichs indem Schlüsselwerte selbst betrachtet werden, um „Abstand“ zum Schlüssel K abzuschätzen nächste Suchposition pos wird aus den Werten ug und og der Unter- und Obergrenze des aktuellen Suchbereichs wie folgt berechnet: K - Inhalt [ug]. Key pos = ug + * (og - ug) Inhalt[og].Key - Inhalt [ug].Key G.Heyer 19 Algorithmen und Datenstrukturen Sinnvoll, wenn der Schlüsselwert im betreffenden Bereich einigermaßen gleichverteilt ist erfordert dann im Mittel lediglich log2 log2n + 1 Schlüsselvergleiche Im schlechtesten Fall (stark ungleichmäßige Werteverteilung) entsteht jedoch linearer Suchaufwand ( O ( n ) ) G.Heyer 20 Algorithmen und Datenstrukturen