Sandbox: Difference between revisions
No edit summary |
No edit summary |
||
Line 91: | Line 91: | ||
* "Teile und herrsche"-Prinzip (divide and conquer) zur Zerlegung in Teilprobleme | * "Teile und herrsche"-Prinzip (divide and conquer) zur Zerlegung in Teilprobleme | ||
* Zusammenführen der Lösungen über Mischen (merging) | * Zusammenführen der Lösungen über Mischen (merging) | ||
** two-way | |||
** multi-way | |||
# <tt>c ← merge(a,b)</tt> | # <tt>c ← merge(a,b)</tt> | ||
Revision as of 22:54, 12 May 2008
hallo
There was a young lady from Riga,
who smiled as she rode on a tiger.
they returned from the ride
with the lady inside
and the smile on the face of the tiger.
hello | is |
---|---|
a | table |
3.Stunde am 16.04.2008
Sortierverfahren
Motivation
Def: Ein Sortierverfahren ist ein Algorithmus, der dazu dient, eine Liste von Elementen zu sortieren.
Anwendungen
- Sortierte Daten sind häufig Vorbedingungen für Suchverfahren (Speziell für Algorithmen mit Log(N) Komplexität)
- Darstellung von Daten gemäß menschlicher Wahrnehmung
- Bemerkung: aus programmiertechnischer Anwenwendungssicht hat das Sortierproblem an Relevanz verloren, da
- Festplatten / Hauptspeicher heute weniger limitierenden Charakter haben, so dass komplizierte, speicher-sparende Sortieralgorithmen nur noch in wenigen Fällen benötigt werden.
- gängige Programmiersprachen heute typenabhängige Algorithmen zur Verfügung stellen. Der Programmierer braucht deshalb sich in den meisten Fällen nicht mehr um die Implementierung von Sortieralgorithmen kümmern. In C/C++ sorgen dafür beispielsweise Methoden aus der STL
Vorraussetzungen/ Spielregeln
Mengentheoretische Anforderungen
- Definition Totale Ordnung/ Total gordnete Menge
Eine Totale Ordnung / Total geordnete Menge ist eine binäre Relation
über einer Menge , die transitiv, antisymmetrisch und total ist.
sei dargestellt als infix Notation dann, falls M total geordnet, gilt
(1) (antisymmetrisch)
(2) (transitiv)
(3) (total)
Bemerkung: aus (3) folgt (reflexiv)
Hab in der Wiki eine gute Seite dazu gefunden Ordnungsrelation
Datenspeicherung
a) Array (Grafik folgt noch)
b) Vekettete Liste
Nachteil Adressierung bsp: 10 > 9
Charakterisierung der Effizienz von Algorithmen
- (a) Komplexität O(1), O(n), etc. wird in Kapitel Effizienz erklärt.
- (b) Zählen der notwendigen Vergleiche
- (c) Messen der Laufzeit mit 'timeit' (auf identischen Daten)
Rekursive Zerlegung zerlegt Ursprüngliche Probleme in kleinere Probleme und wendet sie auf die kleineren Probleme an; daraufhin werden die Teilprobleme zur Lösung des Gesamtproblems verwendet. Aufwand für N Eingaben, hängt ab vom Aufwand der Eingaben geringeren Umfangs ab. (Teilprobleme)
----
4. Stunde, am 17.04.2008
(Fortsetzung der Stunde vom 16.04.2008)
3.3 Mergesort
a) Algorithmus
- Zugrunde liegende Idee:
- "Teile und herrsche"-Prinzip (divide and conquer) zur Zerlegung in Teilprobleme
- Zusammenführen der Lösungen über Mischen (merging)
- two-way
- multi-way
- c ← merge(a,b)
c = merge(a,b) ← { # Kombination zweier sortierter Listen a_i und b_j # zu einer sortierten Ausgabeliste c_k a[M+1] ← maxint b[N+1] ← maxint for k ← 1 to M+N if a[i] < b[j] c[k] > a[i] i ← i+1 else c[k] ← b[j] j ← j+1 }
- rekursiver Mergesort:
mergesort(m) ← { #m ist ein Array if |m| > 1 #True, wenn m mehr als 1 Element hat. a ← mergesort(m[1:<|m|/2]) b ← mergesort(m[(|m|/2)+1:|m|]) c ← merge(a,b) return(c) else return(m) }
(Eine In-place-Implementierung siehe Sedgewick.)
Bei der Sortierung mit Mergesort wird das Array immer in zwei Teile geteilt. → Es
entsteht ein Binärbaum der Tiefe .
Zeitkomplexität:
Komplexität
Komplexität: (für N = )
Erklärungen zur Formel:
- : für jede Hälfte des Arrays
- : für das Zusammenführen
weitere Eigenschaften von MergeSort
- Mergesort ist stabil, weil die Position gleicher Schlüssel im Algorithmus
merge(a,b) nicht verändert wird - wegen „<” hat das linke
Element Vorrang.
- Mergesort ist unempfindlich gegenüber der Reihenfolge der Eingabedaten.
Grund dafür ist die vollständige Aufteilung des Ausgangsarrays in Arrays der Länge
1.
- Diese Eigenschaft ist dann unerwünscht, wenn ein Teil des Arrays oder gar das
ganze Array schon sortiert ist. Es wird nämlich in jedem Fall das ganze Array neu
sortiert.
Quicksort
- Quicksort wurde in den 60er Jahren von Charles Antony Richard Hoare [1] entwickelt. Es gibt viele Implementierungen von Quicksort, siehe vgl. [2].
- Dieser Algorithmus gehört zu den "Teile und herrsche"-Algorithmen (divide-and-conquer) und ist der Standardalgorithmus für Sortieren.
grundlegender Algorithmus
quicksort(l,r) ← { #l: linke Grenze, r: rechte Grenze des Arrays #Das Array läuft also von l bis r (a[l:r]) if r > l i ← partition(l,r) #i ist das Pivot-Element quicksort(l,i-1) #quicksort auf beide Hälfte des Arrays anwenden quicksort(i+1,r) }
Dieser Algorithmus wird rekursiv für zwei Teilstücke links und rechts des Pivot-Elements aufgerufen. Das Pivot-Element ist nach diesem Schritt an der richtigen Position (d.h. links von der Stelle i stehen nur kleinere, rechts von i nur größere Elemente als das Pivot-Element). Die Methode partition sorgt dafür, dass diese Bedingung erfüllt ist.
Algorithmus für partition
Aufgabe: Ordne a so um, dass nach der Wahl von i (Pivot-Element)
gilt:
- ist sortiert, d.h. dieses Element ist am endgültigen Platz.
Abbildung fehlt noch a[i] heißt Pivot-Element (p)
i ← partition(l,r) ← { p ← a[r] #p: Pivot-Element. Hier wird willkürlich das rechteste Element # als Pivot-Element genommen. i ← l-1 #i und j sind Laufvariablen j ← r repeat repeat i ← i+1 #Finde von links den ersten Eintrag >= p until a[i] >= p repeat j ← j+1 #Finde von rechts den ersten Eintrag <= p until a[j] <= p swap(a[i], a[j]) until j <= i #Nachteile: p steht noch rechts swap(a[i], a[j]) #Letzter Austausch zwischen i und j muss #zurückgenommen werden swap(a[i], a[r]) return(i) }
Bemerkungen zur gegebenen Implementierung:
- Sie benötigt ein Dummy-Minimalelement.
- Dieses Element ist durch zusätzliche if-Abfrage vermeidbar, aber die
if-Abfrage erhöht die Komplexität des Algorithmus (schlechte Performanz).
- Sie ist ineffizient für (weitgehend) sortierte Arrays, da sich folgende
Aufteilung für die Partitionen ergibt:
- Erste Partition: [l,i-1], zweite Partition: [i+1,r]
- Die erste Partition umfasst N-1 Elemente
- Die zweite Partition ist leer (bzw. sie existiert nicht), weil das Pivot-Element p = r gewählt wurde. Das Array wird also elementweise abgearbeitet.
- → N einzelne Aufrufe ⇒ Zeitkomplexität: (siehe Berechnung vom 16.04.2008)
- Für identische Schlüssel sollten beide Laufvariablen stehen bleiben.
- Bei der gegebenen Implementierung tauscht auch gleiche Elemente aus.
- Für identische Schlüssel können die Abbruchbedingungen verbessert werden (siehe
Sedgewick).
Komplexität
für
Anmerkungen zur Formel:
- : Vergleiche für jeden Aufruf
- : Teilungspunkt
Für sehr große N gilt:
beziehungsweise
Mittlere Komplexität:
Verbesserungen des Algorithmus
- Eine Verbesserung beseitigt die Rekursion durch Verwendung eines Stacks.
- "r" wird immer kleiner → Der rekursive Aufruf lohnt sich nicht mehr. → Explizites Sortieren einsetzen.
- Das Pivot-Element könnte geschickter gewählt werden: Median.
147.142.207.188 19:31, 23 April 2008 (UTC)