Angewandte Datentechnik Interne Sortierverfahren Interne Sortierverfahren Ausarbeitung einer Maturafrage aus dem Fach A n g e w a n d t e D a t e n t e c h n i k Andreas Hechenblaickner 5CDH HTBLA Kaindorf/Sulm Dipl.-Ing. Manfred Wilfling Erstelldatum: 24. Februar 2003 Letzte Überarbeitung: 7. März 2003
Inhaltsverzeichnis 1 Inhaltsverzeichnis 1 Inhaltsverzeichnis 2 2 Sortierverfahren 3 2.1 Interne und Externe Sortierverfahren 3 2.2 Algorithmen 3 2.3 Stabile Algorithmen 3 3 4 3.1 Bubble Sort Sortieren durch vertauschen 4 3.2 Selection Sort Sortierung durch Auswahl 5 3.3 Insertion Sort Kartenspieler Sortiermethode 6 3.4 Shell Sort 7 3.5 Quick Sort 8 3.6 Verbesserungen von Quick Sort 10 4 Folienvorschlag 12 5 Zusammenfassung 13 6 Quellen 13 HTBLA Kaindorf/Sulm Seite 2 von 13
Sortierverfahren 2 Sortierverfahren "Wer programmieren kann, beherrscht das kleine Einmaleins der Programmierkunst!" Die Aufgabe des Sortierens ist, es eine endliche Menge von Eingabedaten (eine Liste von so genannten Schlüsseln) in eine bestimmte Ordnung zu bringen (aufsteigend oder absteigend). Sortieren ist in der Praxis sehr wichtig, denn in sortierten Listen lassen sich Elemente schnell finden und Duplikate aufspüren. 2.1 Interne und Externe Sortierverfahren Man spricht von internen Sortierverfahren, wenn die zu sortierenden Daten komplett im Hauptspeicher innerhalb einer Datenstruktur einer Programmiersprache gespeichert sind. Gilt es Daten, die auf Datenträgern gespeichert sind (zb in Dateien), zu sortieren, so spricht man von externen Sortierverfahren. Dieses Skriptum beschäftigt sich ausschließlich mit internen Sortierverfahren. 2.2 Algorithmen Grüße Unterschiede gibt es bei verschieden. Es gibt einfach zu programmierende, die bei einer größeren Datenmenge unerträglich lange dauern und komplizierter zu programmierende, die flink sind wie die Wiesel! Im nachfolgenden Kapitel werden die Bubble Sort Selection Sort Insertion Sort Shell Sort Quick Sort näher erklärt. 2.3 Stabile Algorithmen Ein Algorithmus ist stabil, wenn es die relative Reihenfolge gleicher Schlüssel beibehält. Eine alphabetisch sortierte Schülerliste wird nach Noten sortiert. Ein stabiler Algorithmus liefert eine Liste in der Schüler mit den gleichen Noten nach wie vor alphabetisch sortiert sind. Die meisten einfachen Algorithmen sind stabil. HTBLA Kaindorf/Sulm Seite 3 von 13
3 3.1 Bubble Sort Sortieren durch vertauschen Beschreibung des Algorithmus Beim Bubble-Sortierverfahren wird das Feld immer wieder von links nach rechts durchlaufen und falls notwendig, werden jeweils zwei benachbarte Elemente vertauscht. Das Feld ist sortiert, sobald in einem Durchlauf kein Austausch mehr notwendig ist. Struktogramm tausch falsch von i 0, n-2 Ja t a[i] a[i] > a[i+1]? Nein a[i] a[i+1] a[i+1] t tausch wahr bis tausch = falsch Abbildung 3.1.1 Bemerkung Nach dem ersten Durchlauf der äußeren Schleife befindet sich das größte Element am rechten Ende, also am richtigen Platz. Beim zweiten Durchlauf befindet sich das zweitgrößte Element am richtigen Platz und so weiter. Laufzeitverhalten n² Bubble Sort benötigt im ungünstigsten Fall etwa 2 n² Vergleiche und 2 Austauschoperationen (quadratisches Laufzeitverhalten). HTBLA Kaindorf/Sulm Seite 4 von 13
Codierung in Java 1 public static void bubblesort(int[] a) { 2 boolean swap; 3 4 do { 5 swap = false; 6 7 for (int i = 0; i < a.length - 1; i++) { 8 if (a[i] > a[i + 1]) { 9 int t = a[i 10 a[i] = a[i + 1]; 11 a[i + 1] = t; 12 swap = true; 13 } 14 } 15 } while (swap); 16 } 3.2 Selection Sort Sortierung durch Auswahl Beschreibung des Algorithmus Beim Selection-Sortierverfahren wird als erstes das kleinste Feldelement gesucht und mit dem Element an erster Stelle vertauscht. Danach wird das zweitkleinste Element gesucht und mit dem zweiten Element vertauscht. Auf diese Weise wird fortgesetzt bis das Feld sortiert ist. Struktogramm von i 0, n-2 min i von j i+1, n-1 Ja min j t a[i] a[i] a[min] a[min] t a[min] > a[j]? Nein Abbildung 3.2.1 Bemerkung Der Index i wandert von links nach rechts durch das Feld. Die Elemente links von i haben bereits ihre endgültige Position. Das Feld ist sortiert, wenn i den Wert n-1 erreicht hat. Laufzeitverhalten Selection Sort benötigt etwa n² 2 (quadratisches Laufzeitverhalten). Vergleiche und n Austauschoperationen HTBLA Kaindorf/Sulm Seite 5 von 13
Codierung in Java 1 public static void selectionsort(int[] a) { 2 for (int i = 0; i < a.length - 1; i++) { 3 int min = i; 4 5 for (int j = i + 1; j < a.length; j++) { 6 if (a[min] > a[j]) { 7 min = j; 8 } 9 } 10 11 int t = a[i]; 12 a[i] = a[min]; 13 a[min] = t; 14 } 15 } 3.3 Insertion Sort Kartenspieler Sortiermethode Beschreibung des Algorithmus Beim Insertion-Sortierverfahren werden die Elemente Eines nach dem Anderen betrachtet und an den richtigen Platz zwischen den bereits betrachteten Elementen eingefügt. Eventuell müssen die Feldelemente nach hinten gerückt werden. Struktogramm von i 1, n-1 v a[i] j i solange j > 0 und a[j-1] > v a[j] a[j-1] j j-1 a[j] v Abbildung 3.3.1 Bemerkung Der Zähler i durchläuft das Feld von links nach rechts. Die Elemente links von i sind bereits sortiert, befinden sich jedoch noch nicht an ihrer endgültigen Position. Laufzeitverhalten Insertion Sort benötigt etwa n² 4 Vergleiche und n² 8 Austauschoperationen (quadratisches Laufzeitverhalten). Liegen jedoch bereits fast sortierte Daten vor, ist das Laufzeitverhalten von Insertion Sort fast linear. HTBLA Kaindorf/Sulm Seite 6 von 13
Codierung in Java 1 public static void insertionsort(int[] a) { 2 for (int i = 1; i < a.length; i++) { 3 int v = a[i]; 4 int j = i; 5 6 while (j > 0 && a[j - 1] > v) { 7 a[j] = a[j - 1]; 8 j = j - 1; 9 } 10 11 a[j] = v; 12 } 13 } 3.4 Shell Sort Beschreibung des Algorithmus Das Shell-Sortierverfahren ist ein verbessertes Insertion Sort. Bei Shell Sort werden Teile des Feldes (nur jedes h-te Element) sortiert. Das bedeutet das Feld besteht aus mehreren unabhängig sortierten Feldern. Durch ein großes h können Elemente über große Stecken bewegt werden. Wendet man das Verfahren für eine Folge von h an, die mit 1 endet, ist das Feld sortiert. Struktogramm h 1 solange h <= n div 3 h h*3+1 solange h > 0 von i h, n-1 v a[i] j i solange j >= h und a[j-h] > v a[j] a[j-h] j j-h a[j] v h h div 3 Abbildung 3.4.1 Bemerkung Der Algorithmus verwendet die Folge..., 1093, 364, 121, 40, 13, 4, 1 für h. Laufzeitverhalten Shell Sort benötigt etwa 1,25 n Vergleiche und Austauschoperationen. HTBLA Kaindorf/Sulm Seite 7 von 13
Codierung in Java 1 public static void shellsort(int[] a) { 2 int h = 1; 3 4 while (h <= a.length / 3) { 5 h = h * 3 + 1; 6 } 7 8 System.out.println("h: " + h); 9 10 while (h > 0) { 11 for (int i = h; i < a.length; i++) { 12 int v = a[i]; 13 int j = i; 14 15 while (j >= h && a[j - h] > v) { 16 a[j] = a[j - h]; 17 j = j - h; 18 } 19 20 a[j] = v; 21 } 22 23 h = h / 3; 24 } 25 } 3.5 Quick Sort Beschreibung des Algorithmus Quick Sort ist der wahrscheinlich am Meisten angewendete Algorithmus. Er wurde von CAR Hoare im Jahre 1960 entwickelt. Quick Sort ist deshalb so beliebt, weil die Implementierung leicht ist und der Algorithmus für viele unterschiedliche Fälle gut einsetzbar ist. HTBLA Kaindorf/Sulm Seite 8 von 13
Struktogramm Ja v a[r] i l l < r? Nein solange a[i] < v i i + 1 j r - 1 solange a[j] > v j j - 1 Ja t a[i] a[i] a[j] a[i] t solange i < j t a[i] a[a] a[r] a[r] t i < j? Nein quicksort(a, l, i - 1) quicksort(a, i + 1, r) Abbildung 3.5.1 Bemerkung Es wird Rekursion verwendet die Implementierung ohne Rekursion ist zwar schwierig aber ebenfalls möglich. Wenn sich das kleinste Element rechts außen befindet, wird ein so genannter Markenschlüssel benötigt, um die Suche abzubrechen. Grundlegender Algorithmus Teile und Herrsche: Teile das Feld in eine linke und rechte Seite und sortiere beide getrennt, das heißt es gibt ein linke und rechte Schranke zwischen denen sortiert wird. Der Aufruf erfolgt mit quicksort(feld, 0, n-1). Das Entscheidente ist die Auswahl des mittleren Elementes i. Diese Funktion muss die Daten so umordnen, dass folgende Bedingungen für i erfüllt sind: a[i] befindet sich bereits an seinem endgültigen Platz im Feld a[0]...a[i-1] <= a[i] a[i+1]...a[n-1] >= a[i] Strategie: Wähle zuerst willkürlich a[n-1] als das Element, welches in seine endgültige Position gebracht werden soll. Durchsuche dann das Feld von links beginnend bis ein Element gefunden wird, das größer als a[r] (Links-Zeiger) und durchsuche das Feld von rechts beginnend bis ein Element gefunden wird, das kleiner als a[r] ist (Rechts-Zeiger) ist. HTBLA Kaindorf/Sulm Seite 9 von 13
Die beiden Elemente bei denen die Suche unterbrochen wird, sind offensichtlich fehl am Platz tausche sie aus. Verfahre bis sich Links- und Rechts-Zeiger treffen. Laufzeitverhalten Quick Sort benötigt im Durchschnitt n log( n) Schritte. Im ungünstigsten Fall sind jedoch n ² Schritte notwendig. Es ist fast nicht möglich diesen Sortieralgorithmus an Geschwindigkeit zu übertreffen. Codierung in Java 1 public static void quicksort(int[] a, int l, int r) { 2 if (r > l) { 3 int i, j; 4 int v = a[r]; 5 6 do { 7 for (i = l; a[i] < v; i++); 8 for (j = r - 1; a[j] > v; j--); 9 10 if (i < j) { 11 int t = a[i]; 12 a[i] = a[j]; 13 a[j] = t; 14 } 15 } while (i < j); 16 17 int t = a[i]; 18 a[i] = a[r]; 19 a[r] = t; 20 21 quicksort(a, l, i - 1); 22 quicksort(a, i + 1, r); 23 } 24 } 3.6 Verbesserungen von Quick Sort Eine Verbesserung von Quick Sort lässt sich mit Hilfe folgender Techniken erreichen: Beseitigung der Rekursion. Behandlung kleiner Teilfelder. Zerlegung mit Hilfe des mittleren von drei Elementen (Median Of Three) Mit Kombination dieser Techniken kann die Laufzeit um bis zu 30 % verkürzt werden. Beseitigung der Rekursion Es gibt Verfahren um aus einem Algorithmus die Rekursion zu beseitigen. Dies wird mit Hilfe eine Datenstruktur, dem so genannten Stapel, erreicht. HTBLA Kaindorf/Sulm Seite 10 von 13
Behandlung kleiner Teilfelder Quick Sort ruft sich selbst für viele kleine Teilfelder auf. Daher sollte eine möglichst effiziente Methode für kleine fast sortierte Bereiche verwendet werden. Anstatt if (l < r) als Rekursionsboden kann man den Algorithmus derart abändern, dass zb Insertion Sort aufgerufen wird: 1 if (r l <= m) { 2 insertionsort(a); 3 } 4 else { 5... Dabei ist m ein Parameter, dessen Wert zwischen 5 und 25 liegen sollte. Die Verkürzung der Laufzeit beträgt ca 20 %. Median Of Three Es wird ein besseres zerlegendes Element als das Rechte verwendet. Bei Median Of Three wird das mittlere von drei Elementen als das zerlegende Element gewählt. a[m] ist das mittlere Element (int m = (l + r) / 2). Sortiere a[l], a[m], a[r] mit Hilfe der Methode zum Sortieren dreier Zahlen. Tausche das Mittlere mit a[r-1]. Arbeite den Zerlegungsalgorithmus für a[l+1] bis a[r-2] ab. HTBLA Kaindorf/Sulm Seite 11 von 13
Folienvorschlag 4 Folienvorschlag Allgemeines über Sortierverfahren Notwendigkeit Interne / Externe Sortierverfahren Stabile Sortierverfahren Verschiedene Algorithmen (Auswahl) Bubble Sort Sortieren durch vertauschen Selection Sort Sortieren durch Auswahl Insertion Sort Kartenspieler Sortiermethode Shell Sort Insertion Sort mit Behandlung von kleinen Teilfeldern Quick Sort Sortieren mit Divide & Conquer Verbesserungen von Quick Sort HTBLA Kaindorf/Sulm Seite 12 von 13
Zusammenfassung 5 Zusammenfassung In diesem Skriptum wurden folgende Themen behandelt: Notwendigkeit von Sortierverfahren. Unterschied zwischen internen und externen Sortierverfahren. Eigenschaft stabiler. Beschreibung und Codierung der Sortierverfahren Bubble Sort, Selection Sort, Insertion Sort, Shell Sort und Quick Sort. Verbesserungsmöglichkeiten für Quick Sort. 6 Quellen Eigene Mitschriften aus Grundlagen der EDV, 2. Jahrgang. Sortierverfahren in C, Andreas Rittershofer (http://www.dbg.rt.bw.schule.de/lehrer/ritters/info/sort/sort_h.htm) HTBLA Kaindorf/Sulm Seite 13 von 13