Optimale Sortieralgorithmen
Optimale Sortieralgorithmen
Optimale Sortieralgorithmen
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
<strong>Optimale</strong> <strong>Sortieralgorithmen</strong><br />
Gerold Jäger<br />
12. Oktober 2003
Problem<br />
• Für n ∈ N sei S(n) die minimale Anzahl von Vergleichen,<br />
die benötigt wird, um n Elemente zu sortieren.<br />
• Bestimme S(n).<br />
S(n) ≤<br />
Obere Schranke<br />
� �<br />
n<br />
2<br />
= n(n − 1)<br />
2<br />
(ergibt sich aus dem trivialen Sortier-Algorithmus,<br />
bei dem man jedes Element mit jedem anderen<br />
vergleicht)<br />
1
Lineare Erweiterung<br />
Sei M = {1, · · · , n} und r eine Halbordnung auf M.<br />
Die Anzahl der möglichen Ordnungen O mit H ⊆ O<br />
bezeichnet man als lineare Erweiterung e(r).<br />
Beispiele: Man lasse die reflexiven Beziehungen weg.<br />
e(∅) = n!<br />
e((1, 2)) = n!<br />
2<br />
e((1, 2),(3, 4)) = n!<br />
4<br />
e((1, 2),(1, 3)) = n!<br />
3<br />
e((1, 2),(2, 3),(1, 3)) = n!<br />
6<br />
2
Untere Schranke<br />
Für 1 ≤ i �= j ≤ n und r ′ := r ∪ (i, j) und r ′′ :=<br />
r ∪ (j, i) gilt:<br />
e(r) = e(r ′ ) + e(r ′′ )<br />
Wegen e(∅) = n! und max{e(r ′ ),e(r ′′ )} ≤ e(r)<br />
2 folgt:<br />
S(n) ≥ ⌈log 2 n!⌉<br />
3
Algorithmus: binäres Einsortieren<br />
Seien die ersten k−1 Elemente schon sortiert. Das k-te<br />
Element ak wird einsortiert, indem man es mit einem<br />
mittleren Element aller noch nicht mit ak verglichenen<br />
Elemente vergleicht.<br />
Beispiel:<br />
1<br />
2<br />
3<br />
I III II<br />
Man benötigt ⌈log 2 k⌉ Schritte zum Einsortieren.<br />
4<br />
6<br />
5<br />
7<br />
8<br />
4
Algorithmus von Ford, Johnson<br />
(Verfeinerung des binären Einsortierens)<br />
• Vergleiche jeweils zwei neue Elemente, bis ein oder<br />
kein Element übrig ist.<br />
• Es ergeben sich zwei Gruppen. Für ungerades n<br />
nimm das übrige Element zur Gruppe der kleineren<br />
Elemente hinzu.<br />
• Sei n = 2m bzw. n = 2m + 1.<br />
• Sortiere die m größeren Elemente, indem man dieses<br />
Verfahren induktiv von n auf m überträgt.<br />
• Das Einsortieren der n − m kleineren Elemente geschieht<br />
auf folgende Weise (Beispiel n = 19):<br />
5
5<br />
6<br />
J<br />
7<br />
I<br />
8<br />
H<br />
9<br />
G<br />
3<br />
F<br />
Idee: Das Einsortieren in 2 k − 1 Elemente ist<br />
optimal.<br />
4<br />
E<br />
1<br />
D<br />
2<br />
C<br />
A<br />
B<br />
6
n US(n) S(n) FJ(n) BE(n)<br />
1 0 0 0 0<br />
2 1 1 1 1<br />
3 3 3 3 3<br />
4 5 5 5 5<br />
5 7 7 7 8<br />
6 10 10 10 11<br />
7 13 13 13 14<br />
8 16 16 16 17<br />
9 19 19 19 21<br />
10 22 22 22 25<br />
11 26 26 26 29<br />
12 29 30 30 33<br />
13 33 34 34 37<br />
14 37 38 38 41<br />
15 41 ? 42 45<br />
16 45 ? 46 49<br />
17 49 ? 50 54<br />
18 53 ? 54 59<br />
19 57 ? 58 64<br />
20 62 62 62 69<br />
21 66 66 66 74<br />
22 70 71 71 79<br />
23 75 ? 76 84<br />
24 80 ? 81 89<br />
25 84 ? 86 94<br />
47 198 ≤ 200 201 219<br />
7
Sortierbarkeits-Algorithmus<br />
Algorithmus SORT(r,c)<br />
EINGABE M = {1, · · · ,n}, r Halbord. auf M, c ∈ N<br />
(Algorithmus berechnet, ob r [insbesondere für r = ∅]<br />
in c Schritten sortierbar ist)<br />
1 IF e(r) ≤ 2<br />
2 RETURN Sortierbar<br />
3 FOR i = 1, · · · , n − 1<br />
4 FOR j = i + 1, · · · ,n<br />
5 IF (i, j) /∈ r AND (j,i) /∈ r<br />
6 r1 := r ∪ {(i, j)}<br />
7 r2 := r ∪ {(j, i)}<br />
8 IF e(r1) ≤ 2 c−1 AND e(r2) ≤ 2 c−1<br />
9 IF SORT(r1,c−1) AND SORT(r2, c−1)<br />
10 RETURN Sortierbar<br />
11 RETURN Nicht Sortierbar<br />
Nachteile:<br />
• rekursiver Algorithmus ⇒ sehr langsam<br />
• viele r1, r2 werden sowohl bei der Berechnung der<br />
Anzahl der linearen Erweiterungen als auch beim<br />
rekursiven Aufruf von SORT mehrfach getestet<br />
8
Wells Nicht-Sortierbarkeits-Algorithmus<br />
Algorithmus NON-SORT(r,c)<br />
EINGABE M = {1, · · · ,n}, r0 Halbord. auf M, c ∈ N<br />
(Algorithmus versucht zu beweisen, dass r0 insbesondere<br />
für r0 = ∅] nicht in c Schritten sortierbar ist)<br />
1 S0 = {r0}<br />
2 FOR k = 1, · · · , c<br />
3 Sk = ∅<br />
4 FOR EACH r ∈ Sc−1<br />
5 FOR i = 1, · · · , n − 1<br />
6 FOR j = i + 1, · · · ,n<br />
5 IF (i, j) /∈ r AND (j,i) /∈ r<br />
6 r1 := r ∪ {(i, j)}<br />
7 r2 := r ∪ {(j, i)}<br />
8 IF ! ISOM(r1, Sk) AND ! ISOM(r2, Sk)<br />
(Ist r1/r2 zu einem r ′ ∈ Sk isomorph?)<br />
9 IF e(r1) ≤ 2 c−k AND e(r2) ≤ 2 c−k<br />
10 IF e(r1) ≥ e(r2)<br />
11 Sk = Sk ∪ {r1}<br />
12 ELSE<br />
13 Sk = Sk ∪ {r2}<br />
9
14 IF Es gibt eine geordnete Menge in Sc<br />
15 Kein Ergebnis<br />
16 ELSE<br />
17 Nicht sortierbar<br />
Wells Algorithmus benötigt:<br />
Ullmans Algorithmus zum Aufspüren von Graphenisomorphismen<br />
Algorithmus zur Berechnung der Anzahl der linearen<br />
Erweiterungen<br />
Wells Algorithmus liefert:<br />
Für n = 12 ist r0 = ∅ nicht in 29 Schritten sortierbar.<br />
⇒ S(12) = 30<br />
10
Peczarskis Verbesserungen<br />
• Effizientere Implementation<br />
• Verbesserter Algorithmus zur Berechnung der Anzahl<br />
der linearen Erweiterungen<br />
• Neue Idee: Falls der Algorithmus kein Ergebnis liefert,<br />
kann man auf folgende Weise testen, ob auch<br />
in diesem Fall r0 nicht sortierbar ist:<br />
– Wende den Sortierbarkeits-Algorithmus für k =<br />
c − 1, · · · , 1 (soweit der Algorithmus Ergebnisse<br />
liefert) auf alle r ∈ Sk an.<br />
– Falls es ein k = c − 1, · · · , 1 gibt, so dass keine<br />
Menge aus Sk in c − k Schritten sortierbar ist,<br />
dann ist r0 nicht sortierbar.<br />
• Neue Ergebnisse:<br />
S(13) = 34,S(14) = 38,S(22) = 71<br />
11
Sortierbarkeit oder Nicht-Sortierbarkeit<br />
• Frage: Ist für n ∈ N r = ∅ in c Schritten sortierbar?<br />
• Notwendige Bedingung:<br />
e(r) = n! ≤ 2 c<br />
• Für k = 1, · · · , c muss nach dem k-ten Sortierschritt<br />
für die beiden möglichen neuen Halbordnungen r1<br />
und r2 mit e(r) = e(r1) + e(r2) gelten:<br />
max{e(r1), e(r2)} ≤ 2 c−k<br />
• Je größer der Quotient n!<br />
2 c ist, desto mehr kann man<br />
die Nicht-Sortierbarkeit erwarten und desto schneller<br />
ist der Nicht-Sortierbarkeits-Algorithmus fertig.<br />
12
Fälle, für die 2 mögliche S(n) in Frage<br />
kommen<br />
n 12 13 14 15 16 17<br />
n!<br />
2 ⌈log 2 n!⌉ 0.89 0.72 0.63 0.59 0.59 0.63<br />
n 18 19 22 23 24<br />
n!<br />
2 ⌈log 2 n!⌉ 0.71 0.84 0.95 0.68 0.51<br />
Berechnung weiterer Werte von S(n)<br />
• Wells und Peczarskis Nicht-Sortierbarkeits-<br />
Algorithmus liefert nur negative Resultate:<br />
– S(12) > 29 ⇒ S(12) = 30 (Wells)<br />
– S(13) > 33 ⇒ S(13) = 34 (Peczarski)<br />
– S(14) > 37 ⇒ S(14) = 38 (Peczarski)<br />
– S(22) > 70 ⇒ S(22) = 71 (Peczarski)<br />
• Vermutung: S(16) = 45 < 46 = FJ(16)<br />
• Solche verbesserten Algorithmen können nur mit<br />
dem (zu langsamen) Sortierbarkeits-Algorithmus<br />
nachgewiesen werden.<br />
⇒ Verbesserter Sortierbarkeits-Algorithmus!<br />
13
Verbesserter Sortierbarkeits-Algorithmus<br />
Algorithmus NEW-SORT(r,c)<br />
EINGABE M = {1, · · · ,n}, r Halbord. auf M, c ∈ N<br />
(Algorithmus berechnet, ob r [insbesondere für r = ∅]<br />
in c Schritten sortierbar ist)<br />
Ideen des Algorithmus<br />
• Man betrachte c Stufen 0, · · · , c − 1.<br />
• In Stufe k betrachte man Halbordnungen, die in<br />
c − k Schritten sortierbar sind.<br />
• Für jede Halbordnung r ′ in jeder Stufe k gibt es drei<br />
Zustände:<br />
sortierbar=2, nicht sortierbar=1, undefiniert=0.<br />
• Zum Durchführen von Isomorphietests und somit<br />
zum Vermeiden doppelter Berechnungen speichern<br />
wir alle Zwischenergebnisse der Art:<br />
14
′ (in Stufe k) ist in c − k Schritten (nicht)<br />
sortierbar.<br />
• Stufe 0 hat am Anfang den Zustand 0. Hat diese<br />
Stufe den Zustand 2, so ist r sortierbar. Hat sie den<br />
Zustand 1, so ist r nicht sortierbar.<br />
• Wir benutzen folgende Beobachtung:<br />
r ′ ist in k Schritten sortierbar.<br />
⇔ Es gibt 1 ≤ i < j ≤ n, so dass r ′ ∪ {(i, j)}<br />
und r ′ ∪ {(j, i)} in k − 1 Schritten sortierbar sind<br />
• In jeder Stufe außer 0 werden zwei Halbordnungen<br />
betrachtet.<br />
15
• Folgende Zustände sind denkbar:<br />
a) (0, 0) oder (2,0) (bzw. (0) in Stufe 0)<br />
∗ Erhöhe die Stufe um 1.<br />
∗ Addiere zu r ′ aus der letzten Stufe ein noch<br />
nicht betrachtetes Paar (i, j).<br />
∗ Mögliche Zustände in der neuen Stufe:<br />
· (0,0): Keine Informationen.<br />
· (1,0), (2,0), (2, 1),(2, 2): Informationen durch<br />
Isomorphietests.<br />
b) (1, 0) oder (2,1)<br />
∗ Verringere die Stufe um 1.<br />
∗ Mögliche Zustände in der neuen Stufe:<br />
· (0,0), (2,0): Man kann noch weitere Paare<br />
testen.<br />
· (1,0), (2,1) (bzw. (1) in Stufe 0): Man hat<br />
alle Paare getestet.<br />
c) (2, 2)<br />
∗ Verringere die Stufe um 1.<br />
∗ Mögliche Zustände in der neuen Stufe:<br />
· (2,0): Man muss noch das umgekehrte Paar<br />
testen.<br />
16
· (2,2) (bzw. (2) in Stufe 0): Man hat beide<br />
Paare getestet.<br />
d) (0, 1), (0,2)<br />
· Nicht möglich, da definitionsgemäß das erste<br />
Paar immer zuerst betrachtet wird.<br />
e) (1, 1), (1,2)<br />
· Nicht möglich, da wenn ein Paar keine sortierbare<br />
Halbordnung liefert, das umgekehrte<br />
Paar nicht mehr betrachtet werden muss.<br />
• Weiter wird benutzt, dass eine Halbordnung r ′ in<br />
1 Schritt sortierbar ist, genau dann wenn e(r ′ ) ≤ 2<br />
ist.<br />
Vorteile im Vergleich zum<br />
Original-Algorithmus<br />
• Nicht-rekursiver Algorithmus.<br />
• Durch Isomorphietests Vermeiden von doppelten<br />
Rechnungen.<br />
17