Praktische Einführung und Programmierung
Stefan Bosse
Universität Koblenz - FB Informatik
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren ::
Bisher waren die drei wichtigsten Operationen auf Abstrakten Datentypen:
Ein weiteres grundlegendes Problem in der Informatik neben dem Suchen ist das Sortieren.
Bereits bei den Listen und dann bei den Bäumen war Restrukturierung wichtig um optimale Rechenzeiten zu erzielen
Sortieren von Elementen ist Restrukturierung
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Taxonomie der Sortierverfahren
Unter Sortieren versteht man das Anordnen einer Menge von Objekten in einer bestimmten Ord-nung. Diese Ordnung kann z. B. bei numerischen Daten durch die größer/kleiner-Relation oder bei Texten durch die lexikografische Reihenfolge gegeben sein.
Die zu sortierenden n Elemente seien in einem Feld a mit den Komponenten a[0], a[1], ... , a[n − 1] gespeichert.
Sortieren bedeutet nun, dass die Feldkomponenten durch eine Permutation i1 , i2 , ... , in der Indizes 0, 1, ... , n − 1 in diejenige Reihenfolge gebracht werden, die der gewünschten Ordnung, ausgedrückt durch eine Ordnungsrelation ≤f , entspricht:
a[i1],a[i2],a[i3],…,a[in]mita[i1]≤fa[i2]≤fa[i3]≤f…≤fa[in]
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Taxonomie der Sortierverfahren
Der Sinn des Sortierens bzw. Ordnens liegt darin, dass der Zugriff auf Datensätze in einer geordneten Datei oder Datenstruktur wesentlich effizienter und schneller vonstatten geht, als in einer nicht geordneten Anordnung.
Untersuchungen haben ergeben, dass auf kommerziellen Anlagen ca. 25% der CPU-Zeit auf Sortierläufe entfällt.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Taxonomie der Sortierverfahren
Es existiert eine große Anzahl von Sortieralgorithmen unter denen man im Einzelfall den geeig-netsten auswählen muss.
Die Sortiermethoden hängen stärker als die meisten anderen Algorithmen von der Struktur der zu sortierenden Daten ab.
Es ist ein ganz wesentlicher Unterschied, ob man die zu sortierenden Daten im relativ beschränkten Hauptspeicher mit wahlfreiem Zugriff oder auf langsameren, jedoch größeren sequentiell oder zyklisch arbeitenden externen Speichermedien – also auf Band- oder Plattenlaufwerken – halten muss.
Gerade bei Sortieralgorithmen spielen auch kleine Leistungssteigerungen eine große Rolle, da sich dies wegen der Häufigkeit von Sortierläufen sehr stark auswirken kann.
Komplexitätsberechnungen sind oft nichttrivial.
Bei Algorithmen mit im Normalfall hervorragendem Zeitverhalten kann das Verhalten im ungünstigsten Fall (worst case) katastrophal sein.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Taxonomie der Sortierverfahren
Welche dramatischen Effekte die Verbesserung der Komplexitätsordnung eines Sortierverfahrens haben kann, zeigt das Beispiel einer 1987 in der damaligen Bundesrepublik Deutschland durchgeführten Volkszählung.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Taxonomie der Sortierverfahren
Stabilität von Sortierverfahren: Nehmen wir eine Liste mit Daten zu Personen an, die alphabetisch nach den Namen sortiert ist. Wird diese Liste nun nach dem Alter der Personen sortiert, so werden bei Anwendung eines stabilen Verfahrens Personeneinträge mit dem gleichen Alter auch weiterhin alphabetisch geordnet sein.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Taxonomie der Sortierverfahren
Sortierbare Aggregationen (Datenstrukturen/Objekte):
Zwei Speicherklassen werden unterschieden:
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Taxonomie der Sortierverfahren
Gemäß den Speicherklassen kann man direkte und indirekte Sortierverfahren unterscheiden.
Drei einfache, direkte Sortierverfahren, die ein gegebenes Feld a[i] von Objekten am Platz ordnen:
Die Umstellung der Elemente geschieht dabei auf dem Eingabe-Array, das dann bei der Ausgabe die geordneten Daten enthält.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Einfügen
Man geht von einem Array a mit n Komponenten und Indizierung von 0 bis n − 1 aus. Nun wird a in zwei Intervalle aufgeteilt, die Zielsequenz a[0] bis a[i − 1] und die Quellensequenz a[i] bis a[n − 1]. Beginnend mit i = 1 wird bei jedem Schritt das Element a[i] aus der Quellensequenz entfernt und an der durch die Ordnungsrelation gegebenen Stelle in die Zielsequenz eingefügt.
InsertionSort am Beispiel
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Einfügen
function insertionSort(array) { for (i = 1; i < length(array); i++) { j = i; m = array[i]; m = array[i].key; // für alle Elemente links vom Marker-Feld while (j > 0 && array[j − 1] > m) { .. array[j-i].key... // verschiebe alle größeren Elemente nach hinten array[j] = array[j − 1]; j−− ; } // setze m auf das freie Feld array[j] = m; }}
Sortieren durch Einfügen bzw. Verschieben mit einem Array. Die Arrayelemente können auch Datenstrukturen sein und ein Attribute key bestimmt die Sortierung.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Einfügen
Zur Berechnung der Komplexität berücksichtigt man,
Cmin(n)=n−1,Cmax(n)=n2−n2,Cavg(n)=n2+n−24Mmin(n)=3(n−1),Mmax(n)=n2+3n−42,Mavg(n)=n2+9n−104
mit C als Gesamtkomplexität für den Vergleich und M für das Verschieben.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Einfügen
Die Komplexität ist also im Mittel sowohl für C(n) als auch für M(n) von der Ordnung O(n2).
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Selektion
SelectionSort am Beispiel
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Selektion
function swap (array,idx1,idx2) { t=array[idx1] array[idx1]=array[idx2] array[idx2]=t}function maxIndex(array,idx) { maxi=idx maxv=array[idx] for (var i=0;i<idx;i++) { if (array[i]>maxv) { maxi=i maxv=array[i] } } return maxi}function selectionSort(array) { p=length(array)-1 while(p) { g = maxIndex(array,p) swap (array,p,g) p-- }}
Sortieren durch Selektion, auch hier ein in-place Verfahren. Die wichtigsten Schritte sind Suche und Vertauschung (swap)
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Vertauschen
Eines der bekanntesten, wenn auch kein besonders effizientes Sortierverfahren ist BubbleSort.
Der Name ist aus der Vorstellung abgeleitet, dass sich bei einer vertikalen Anordnung der Elemente der Folge verschieden große, aufsteigende Blasen (»Bubbles«) wie in einer Flüssigkeit von allein sortieren, da die größeren Blasen die kleineren »überholen«.
Das Grundprinzip besteht demzufolge darin, die Folge immer wieder zu durchlaufen und dabei benachbarte Elemente, die nicht der gewünschten Sortierreihenfolge entsprechen, zu vertauschen.
Elemente, die größer als ihre Nachfolger sind, überholen diese daher und steigen zum Ende der Folge hin auf.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Vertauschen
function BubbleSort (array) // Eingabe: zu sortierende Folge F der Länge n do { swaps=0 for (i=0;i<n;i++) { if (array[i]> array[i + 1]) { swap(array,i,i+1) swaps++ } } } while (swaps==0)}
Nachbarschaftsvergleich und Vertauschung
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Vertauschen
Bubblesort im Beipiel, Gezeigt sind nur Schritte wo eine Vertauschung stattfindet.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Vertauschen
Der Algorithmus weist schon eine Verbesserung gegenüber der ursprünglichen Idee auf, indem die Folge nicht n · n-mal durchlaufen wird, sondern der Abbruch bereits dann erfolgt, wenn keine Vertauschung mehr stattgefunden hat.
Eine weitere Optimierung ist dass in jedem Durchlauf das jeweils größte Element an das Ende bewegt wird. Daher genügt es, im zweiten Durchlauf nur den Bereich 1 … n − 2, im dritten Durchlauf den Bereich 1 … n − 3 usw. zu betrachten.
Schließlich kann auch noch »Lokalität« von Feldzugriffen speziell bei großen Folgen ausgenutzt werden, indem der Durchlauf abwechselnd auf- bzw. abwärts erfolgt.
Nicht nur die Rechenkomplexitätsklasse ist relevant, auch die Implementierung im Detail, die signifikanten Einfluss auf die Rechenzeit haben kann.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Vergleich Sortierenverfahren
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Mischen
MergeSort: Die bisher vorgestellten Verfahren erfordern einen direkten Zugriff auf einzelne Elemente der Folge und sind daher nur für internes Sortieren geeignet. Sollen dagegen Dateien sortiert werden, die nicht in den Hauptspeicher passen, müssen andere Verfahren zum Einsatz kommen. Eine Möglichkeit ist hier, das Sortieren in zwei Schritten oder Phasen auszuführen:
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Mischen
Dieses MergeSort-Verfahren lässt sich aber auch für das interne Sortieren anwenden. Hierbei wird zunächst die zu sortierende Folge in zwei Teilfolgen zerlegt, diese werden durch rekursive Anwendung von MergeSort sortiert und anschließend gemischt.
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Mischen
Der Algorithmus ist aufgeteilt in:
Aufteilen, Verarbeiten, und Zusammenführung
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Mischen
function MergeSort (array) { // Eingabe: eine zu sortierende Folge F // Ausgabe: eine sortierte Folge FS n = length(array) if (n==1) // einelementig then return array else { // Teile F in F1 und F2; splitIndex = n/2 F1 = slice(array,0,splitIndex-1) F2 = slice(array,splitIndex,n-1) F1 = MergeSort (F1) F2 = MergeSort (F2) return Merge (F1, F2) }}
Grundgerüst des Sortieren durch Mischen
Stefan Bosse - Algorithmen und Datenstrukturen - Modul S Sortierverfahren :: Sortieren durch Mischen
Der Vorgang des Mischens erfordert in der Regel doppelten Speicherplatz, da ja eine neue Folge aus den beiden sortierten Folgen erzeugt wird. Eine Alternative ist das Mischen in einem Feld, allerdings ist hier ein aufwendigeres Verschieben notwendig.