|
|
(17 intermediate revisions by 12 users not shown) |
Line 1: |
Line 1: |
| | Formel: |
| | <math> |
| | \Delta L_{sum} = \frac{\sqrt{L_R^4 \cdot \Delta L_B^2 + L_B^4 \cdot \Delta L_R^2}}{(L_B + L_R)^2} |
| | </math> |
| | --- |
| <math>f(x)=\sqrt[4]{x}</math> | | <math>f(x)=\sqrt[4]{x}</math> |
|
| |
|
Line 5: |
Line 10: |
| hallo''' | | hallo''' |
|
| |
|
| | <math>L_{iij}</math> |
| | |
| | <math> |
| | X_{ij} = x_i x_j |
| | </math> |
|
| |
|
| There was a young lady from Riga, | | There was a young lady from Riga, |
Line 17: |
Line 27: |
|
| |
|
| {| border="1" cellspacing="0" cellpadding="9" align="center" | | {| border="1" cellspacing="0" cellpadding="9" align="center" |
| ! hello | | ! hello |
| ! is | | ! is |
| |- | | |- |
Line 24: |
Line 34: |
| |- | | |- |
| |} | | |} |
| | 5 |
|
| |
|
| ----
| | / \ |
| 3.Stunde am 16.04.2008
| |
|
| |
|
| ==Sortierverfahren==
| | 2 8 |
|
| |
|
| === Motivation ===
| | / \ / \ |
| '''Def:'''
| |
| Ein Sortierverfahren ist ein Algorithmus, der dazu dient, eine Liste von Elementen zu sortieren.
| |
|
| |
|
| '''Anwendungen'''
| | 1 4 7 9 |
| * 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 [http://de.wikipedia.org/wiki/Standard_Template_Library STL]
| |
|
| |
|
| === Vorraussetzungen/ Spielregeln ===
| | This is a sentence. |
| ==== Mengentheoretische Anforderungen====
| |
| ;Definition Totale Ordnung/ Total gordnete Menge:
| |
| Eine Totale Ordnung / Total geordnete Menge ist eine binäre Relation
| |
| <math>R \subseteq M \times M</math> über einer Menge <math>M</math>, die transitiv, antisymmetrisch und total ist.<br>
| |
| | |
| <math>R</math> sei dargestellt als infix Notation <math>\le </math> dann, falls M total geordnet, gilt
| |
| <math> \forall a,b,c \ \epsilon M </math> <br/>
| |
| (1) <math>a \le b \bigwedge b \le a \Rightarrow a=b </math> (antisymmetrisch)<br/>
| |
| (2) <math>a \le b \bigwedge b \le c \Rightarrow a \le c </math> (transitiv)<br/>
| |
| (3) <math>a \le b \bigvee b \le a </math> (total) <br/>
| |
| Bemerkung: aus (3) folgt <math> a \le a </math> (reflexiv) <br/>
| |
| | |
| ''Hab in der Wiki eine gute Seite dazu gefunden [http://de.wikipedia.org/wiki/Ordnungsrelation'' 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
| |
| <br/>
| |
| (Fortsetzung der Stunde vom 16.04.2008)
| |
| <br/>
| |
| | |
| | |
| === 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
| |
| ==== a.1) Algorithmus <tt>c ← merge(a,b)</tt> ====
| |
| | |
| 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
| |
| }
| |
| | |
| | |
| ==== a.2)'''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 bei Sedgewick.)
| |
| | |
| Bei der Sortierung mit Mergesort wird das Array immer in zwei Teile geteilt. → Es entsteht ein Binärbaum der Tiefe <math>lgN</math>.
| |
| | |
| Gegebene unsortierte Liste: [S,O,R,T,I,N,G]
| |
| Die Teile werden bei jedem Schritt paarweise gemischt.
| |
| | |
| Schritt 0:
| |
| S 0 R T I N G S O R T I N G #Arraylänge: N/8
| |
| Schritt 1: \ / \ / \ / /
| |
| OS RT IN G OS RT IN / #Arraylänge: N/4 Vergleiche: N/4 * 4
| |
| Schritt 2: \ / \ /
| |
| ORST GIN ORST GIN #Arraylänge: N/2 Vergleiche: N/2 * 2
| |
| \ /
| |
| Schritt3: \ /
| |
| GINORST GINORST #Arraylänge: N Vergleiche: N
| |
| | |
| | |
| | |
| Zeitkomplexität: <math>C(N) - N \cdot lgN</math>
| |
| | |
| ==== b) Komplexität ====
| |
| Komplexität: <math>C(N) = 2 \cdot C \left( \frac{N}{2} \right) + N = N \cdot log_2 N </math> (für N = <math>2^n</math> )
| |
| | |
| Erklärungen zur Formel:
| |
| * <math> C \left(\frac{N}{2}\right) </math>: "für jede Hälfte des Arrays"
| |
| * <math> +N </math>: für das Zusammenführen
| |
| * N Vergleiche pro Ebene
| |
| * Insgesamt gibt es <math> log_2 N </math> Ebenen.
| |
| | |
| ==== c) Weitere Eigenschaften von MergeSort ====
| |
| | |
| * Mergesort ist '''stabil''', weil die Position gleicher Schlüssel im Algorithmus <tt>merge(a,b)</tt> nicht verändert wird - wegen <tt>„<”</tt> hat das linke Element Vorrang.
| |
| * Mergesort ist '''unempfindlich gegenüber der ursprünglichen 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 [http://de.wikipedia.org/wiki/C._A._R._Hoare] entwickelt. Es gibt viele Implementierungen von Quicksort, siehe vgl. [http://de.wikipedia.org/wiki/Quicksort].
| |
| * Dieser Algorithmus gehört zu den "Teile und herrsche"-Algorithmen (divide-and-conquer) und ist der Standardalgorithmus für Sortieren.
| |
| | |
| ==== Zugrunde liegender 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 <tt>partition</tt> ====
| |
| Aufgabe: Ordne <tt>a</tt> so um, dass nach der Wahl von <tt>i</tt> (Pivot-Element)
| |
| | |
| gilt:
| |
| # <math>a[i]</math> ist sortiert, d.h. dieses Element ist am endgültigen Platz.
| |
| # <math>\forall x \in \left\{ a \left[ l \right] , ... a \left[ i-1 \right]
| |
| | |
| \right\} : x \leq a \left[ i \right]</math>
| |
| # <math>\forall x \in \left\{ a \left[ i+1 \right], ... a \left[ r \right]
| |
| | |
| \right\} : x \geq a \left[ i \right]</math>
| |
| | |
| [[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)
| |
| }
| |
| | |
| [[Abbildung fehlt noch]]
| |
| | |
| [[Beispiel fehlt noch]]
| |
| | |
| Bemerkungen zur gegebenen Implementierung:
| |
| # Sie benötigt ein Dummy-Minimalelement.
| |
| #* Dieses Element ist durch zusätzliche <tt>if</tt>-Abfrage vermeidbar, aber die
| |
| | |
| <tt>if</tt>-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: <tt>[l,i-1]</tt>, zweite Partition: <tt>[i+1,r]</tt>
| |
| # Die erste Partition umfasst <tt>N-1</tt> Elemente
| |
| # Die zweite Partition ist leer (bzw. sie existiert nicht), weil das Pivot-Element <tt>p = r</tt> gewählt wurde. Das Array wird also elementweise abgearbeitet.
| |
| # → <tt>N</tt> einzelne Aufrufe ⇒ Zeitkomplexität: <math>\approx
| |
| | |
| \frac{N^2}{2}</math> (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 ====
| |
| | |
| <math>C(N) = (N+1) + \frac{1}{N} \sum_{m=1}^{N} \left[ C(k-1) + C(N-k)
| |
| | |
| \right]</math> für <math> N>1;\, C_1 = C_0 =0 </math>
| |
| | |
| Anmerkungen zur Formel:
| |
| # <math>(N+1)</math>: Vergleiche für jeden Aufruf
| |
| # <math>k</math>: Teilungspunkt
| |
| <br/><br/><br/>
| |
| <math>
| |
| \frac{1}{N} \sum_{m=1}^{N} \left[ C(k-1) + C(N-k) \right] = 2 \frac{1}{N}
| |
| | |
| \sum_{k=1}^{N} C(k-1)
| |
| </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| C(N) = (N+1) + \frac{1}{N} \sum_{m=1}^{N} \left[ C(k-1) + C(N-k) \right]
| |
| \overset{\cdot N}{\longleftrightarrow} </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| N \cdot C(N) = N \left[ (N+1) + \frac{2}{N} \sum_{k=1}^{N} C(k-1) \right]
| |
| \overset{-\, (N-1) \cdot C(N-1)}{\longleftrightarrow} </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| N \cdot C(N) - (N-1) \cdot C(N-1) = N(N+1) - (N-1) \cdot N + 2 \sum_{k=1}^{N}
| |
| | |
| C(k-1) - 2 \sum_{k=1}^{N} C(k-1) </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| = N(N+1) - (N-1) \cdot N + 2 \cdot C(N-1) \longleftrightarrow </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| N \cdot C(N) = N(N+1) - (N-1) \cdot N + 2 \cdot C(N-1) + (N-1) + (N-1) \cdot
| |
| | |
| C(N-1) = 2N + (N+1) \cdot C(N-1) \overset{/N(N+1)}{\longleftrightarrow} </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| \frac{C(N)}{N+1} = \frac{C(N-1)}{N} + \frac{2}{N+1} </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| = \frac{C(N-2)}{N-1} + \frac{2}{N} + \frac{2}{N+1} </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| = \frac{C(N-3)}{N-2} + \frac{2}{N-1} + \frac{2}{N} + \frac{2}{N+1} </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| = ... = </math>
| |
| <br/><br/>
| |
| | |
| <math>
| |
| = \frac{C(2)}{3} + 2 \sum_{k=3}^{N} \frac{1}{k+1} \approx 2 \sum_{k=3}^{N}
| |
| | |
| \frac{1}{k+1} \approx 2 \int_1^N \frac{1}{k} dk = 2 \cdot ln N
| |
| </math>
| |
| <br/><br/><br/>
| |
| Für sehr große N gilt:
| |
| <math>\approx 2 \sum_{k=1}^{N} \frac{1}{k}</math> beziehungsweise <math> \geq 2
| |
|
| |
|
| \sum_{k=1}^{N} \frac{1}{k}</math>
| | This sentence is false. |
| <br/><br/>
| | And this one is unprovable! |
| Mittlere Komplexität:
| |
| <math>C(N) = 2(N+1) \cdot lnN \approx 2N \cdot lnN </math>
| |
| <br/><br/><br/>
| |
| ==== 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.
| |
| <br/>
| |
| [[Special:Contributions/147.142.207.188|147.142.207.188]] 19:31, 23 April 2008 (UTC)
| |