Programmieren I Kapitel 7. Sortieren und Suchen
Kapitel 7: Sortieren und Suchen Ziel: Varianten der häufigsten Anwendung kennenlernen Ordnung Suchen lineares Suchen Binärsuche oder Bisektionssuche Sortieren Eigenschaften und Idee Beispiele: Selection, Insertion, Quick, Mergesort, evtl. Bucketsort
Ordnungen reflexiv a <= a transitiv a <= b und b <= c dann a <= c (antisymmetrisch) a <= b und b <= a dann a = b partiell vs. total (nicht) alle Elemente sind vergleichbar
Lineare Suche Eingabe: ein Array a mit Daten; ein Element x Ausgabe: kommt x in a vor? oder: welchen Index hat x in a? Voraussetzung: Test auf Gleichheit Idee: laufe durch das Array, bis der Eintrag gefunden ist. Abbruch des Durchlaufs mit break; Auswertung, ob der Durchlaufindex < a.length Aufwand: Zeit: O(n), Durchschnitt: n/2 Elegante Verallgemeinerung (nicht in JAVA): Prädikat (boolwertige Funktion) als Parameter Failure Resultat bei Variante 2 wird oft unsauber gelöst
Bisektionssuche (Binäre Suche) Eingabe: ein Array a mit sortierten (!) Daten; ein Element x Ausgabe: kommt x in a vor? oder: welchen Index hat x in a? Voraussetzung: Test auf Gleichheit; Ordnung der Elemente Idee: schau in der Mitte des Arrays nach ob das Element kleiner als x ist => suche in der linken Arrayhälfte größer als x ist => suche in der rechten Arrayhälfte gleich x ist => Rückgabe von true oder Indexwert solange, bis aktueller Arraybereich leer ist => Rückgabe false/fail logarithmischer Aufwand: O(log n) Prinzip: schrumpfender Suchraum; Zusicherung: Invariante
Sortieren Grundprinzip Eingabe: ein unsortiertes Array Ausgabe: ein sortiertes Array Voraussetzung: Ordnung der Elemente Erste Idee (für viele Sortierverfahren): so lange es Fehlstellungen gibt, d.h.: i<j und a[i]>a[j], vertausche die Elemente void swap (long[] a, int i, int j) { long aux = a[i]; a[i] = a[j]; a[j] = aux; }
Sortieren Grundprinzip und Überblick Verfeinerte Idee: Anstatt das Array auf einmal zu sortieren, zerlege es, sortiere die Teile und mische die sortierten Teile zusammen (divide and conquer) D&C teilt typischerweise in etwa gleiche Teile; wir erlauben aber auch 1 vs. (n 1) Teilung Klassifizierung: Aufwand beim Aufteilen oder Zusammenmischen
Sortieren Grundprinzip und Überblick Klassifizierung: Weitere Kriterien: stabile Verfahren: ändern die Reihenfolge von gleichen Elementen nicht in situ Verfahren: brauchen keinen (nur O(1)) Hilfsspeicher Art der Aufwand steckt in Zerlegung Zerlegung Mischen 1 + Rest Selection sort Insertion sort gleiche Teile Quicksort Mergesort
Selection sort Idee: dann wiederhole dasselbe für den Bereich 1.. a.length 1 u.s.w. bis der Bereich leer wird Aufwand: Vergleiche: (n 1) + (n 2) +... + 2 + 1 = O(n 2 ) sortiert unsortiert w j suche das kleinste Element im Bereich 0.. a.length 1 und stelle es ganz nach links (in diesem Bereich) Vertauschungen (worst case): O(n) [im Durchschnitt n/2] Gesamt: O(n 2 ) Eigenschaften: in situ, nicht stabil (weil linkes Element zufällig nach rechts geswappt wird)
Insertion sort sortiert unsortiert j w nimm der Reihe nach das 1., 2., 3.,... Element und Idee: wenn es für seine Position zu klein ist, dann tausche es so lange mit seinem linken Nachbarn, bis es passt Aufwand: Vergleiche und Vertauschungen (worst case) je: 1 + 2 +... + (n 2) + (n 1) = O(n 2 ) [im Durchschnitt die Hälfte] Gesamt: O(n 2 ) Eigenschaften: in situ, stabil Verbesserung: statt Einzelvertauschung suche (log!) Platz und mache efiizienten (aber trotzdem linearen) Speichershift
Quicksort Idee: schiebe (swappe) alle kleinen Werte in die linke, und die großen in die rechte Hälfte und sortiere beide Teile unabhängig rekursiv (kein Mischen nötig!) klein und groß im Vergleich zu einem Pivot Element, z.b. dem ersten Eintrag im zu sortierenden Teilarray Aufwand: im Mittel: O(n*log n): Anzahl der Swaps: n + 2* n/2 + 4 * n/4 +... [log n viele Smd.en] im worst case: O(n 2 ) Eigenschaften: in situ, nicht stabil
Quicksort quicksort: rearrange < p = p sort >p sort rearrange: < p = p x? >p b w r return new Pair(b,r)
Mergesort Idee: teile das Array in zwei gleich große Teile (ohne weitere Bedingung), kopiere die Teile in Hilfsrarrays und sortiere diese rekursiv beim Mischen nimm jeweils das kleinere der beiden Minima zuerst in das Ergebnisarray auf (und setze den entsprechenden Minimumszeiger eins weiter) Aufwand: Zeit immer: O(n*log n): in jedem der log n Schritte: n Elemente verteilen und (nach der Rekursion) einzeln zurückkopieren. Platz: O(n) wegen des Hilfsarrays, daher: Eigenschaften: nicht in situ, aber stabil
Mergesort a b a b a i copy m j i m j i m j i m j merge sort(b,a,i,m) sort(a,b,m+1,j) i m j
Bucket sort Voraussetzung: die möglichen Werte der Sortierschlüssel sind bekannt Idee: die Werte der Sortierschlüssel aufzählen und dann die Daten der Reihe nach in die richtigen Schlüssel buckets einhängen Aufwand: linear Typisches Beispiel: Sortierung nach dem ersten Buchstaben des Namens
Zusammenfassung Ordnung Suchen lineares vs. binäres Suchen Sortieren divide & conquer Klassifizierung: wie wird geteilt? wann ist der Aufwand? Beispiele: Selection, Insertion, Quick, Mergesort Sonderfall: Bucketsort häufigste Computeranwendung kennengelernt am effizientesten in der Praxis: Hybridverfahren