Algorithmen und Datenstrukturen

Werbung
Algorithmen und Datenstrukturen
Wintersemester 2012/13
11. Vorlesung
Sortieren in Linearzeit
Prof. Dr. Alexander Wolff
Lehrstuhl für Informatik I
Eine untere Schranke
Frage:
Wieviele Vergleiche braucht jeder vergleichsbasierter
Sortieralg. im worst case um n Objekte zu sortieren?
M.a.W. Gegeben
– ein beliebiger vergleichsbasierter Sortieralgorithmus,
– eine Zahl n von zu sortierenden Objekten,
welche Höhe hat der Entscheidungsbaum mindestens?
Beob.: Die Höhe ist eine Funktion der Blätteranzahl.
Anz. Blätter = Anz. Permutationen von n Obj. = n!
Höhe Binärbaum mit B Blättern ≥ dlog2 B e
Pn
Höhe Entscheidungsbaum ≥ log2 n! =
i =1 log2 i
Rn
Rn
Rn
1
1
partielle
≥ 1 log2 x dx = ln 2 1 ln x dx = ln 2 1 1 · ln x dx
Integration
Rn
n(ln n)−(n−1)
1
1
n
=
(
x
ln
x
|
dx
)
−
x
·
=
R 0
R
1
ln 2
ln 2
x
1
u v = uv − uv 0
∈ Ω (n log n)
Also. . .
Satz.
Jeder vergleichsbasierte Sortieralg. benötigt im worst
case Ω (n log n) Vergleiche um n Objekte zu sortieren.
Korollar. MergeSort und HeapSort sind asymptotisch
worst-case-optimale vergleichsbasierte Sortieralg.
Wir durchbrechen die Schallmauer
(
SpaghettiSort sortiert Spaghetti nach Länge ;-)
CountingSort
sortiert Zahlen in {0, . . . , k }
RadixSort
sortiert s -stellige b -adische Zahlen
BucketSort
sortiert gleichverteilte zufällige Zahlen
aus:
www.marions-kochbuch.de
CountingSort
Idee: 1) für jedes x in der Eingabe: zähle die Anzahl der Zahlen ≤ x
2) benütze diese Information um x im Ausgabefeld
direkt an die richtige Position zu schreiben
Variable:
A
B
Eingabefeld
Ausgabefeld
C
k
Rechenfeld
begrenzt Universum: {0, . . . , k}
Bsp: 1a) Für jedes x in A, zähle die Anz. der Zahlen gleich x
1
2
3
4
5
6
7 8
A 3 0 4 1 3 4 1 4
0
⇒
1
2
3
4
C 1 2 0 2 3
1b) Für jedes x in A, berechne die Anz. der Zahlen ≤ x
C 1 3
0
1
2
3
4
CountingSort
Idee: 1) für jedes x in der Eingabe: zähle die Anzahl der Zahlen ≤ x
2) benütze diese Information um x im Ausgabefeld
direkt an die richtige Position zu schreiben
Variable:
A
B
Eingabefeld
Ausgabefeld
C
k
Rechenfeld
begrenzt Universum: {0, . . . , k}
Bsp: 1a) Für jedes x in A, zähle die Anz. der Zahlen gleich x
1
2
3
4
5
6
7 8
A 3 0 4 1 3 4 1 4
0
⇒
1
2
3
4
C 1 2 0 2 3
1b) Für jedes x in A, berechne die Anz. der Zahlen ≤ x
C 1 3 3 5 8
0
1
2
3
4
2) Schreibe jedes x in A direkt an die richtige Position in B
B
1
2
3
4
5
6
7 8
CountingSort
Idee: 1) für jedes x in der Eingabe: zähle die Anzahl der Zahlen ≤ x
2) benütze diese Information um x im Ausgabefeld
direkt an die richtige Position zu schreiben
Variable:
A
B
Eingabefeld
Ausgabefeld
C
k
Rechenfeld
begrenzt Universum: {0, . . . , k}
Bsp: 1a) Für jedes x in A, zähle die Anz. der Zahlen gleich x
1
2
3
4
5
6
7 8
A 3 0 4 1 3 4 1 4
0
⇒
1
2
3
4
C 1 2 0 2 3
1b) Für jedes x in A, berechne die Anz. der Zahlen ≤ x
C 1 3 3 5 8
0
1
2
3
4
2) Schreibe jedes x in A direkt an die richtige Position in B
4
B
1
2
3
4
5
6
7 8
CountingSort
Idee: 1) für jedes x in der Eingabe: zähle die Anzahl der Zahlen ≤ x
2) benütze diese Information um x im Ausgabefeld
direkt an die richtige Position zu schreiben
Variable:
A
B
Eingabefeld
Ausgabefeld
C
k
Rechenfeld
begrenzt Universum: {0, . . . , k}
Bsp: 1a) Für jedes x in A, zähle die Anz. der Zahlen gleich x
1
2
3
4
5
6
7 8
A 3 0 4 1 3 4 1 4
0
⇒
1
2
3
4
C 1 2 0 2 3
1b) Für jedes x in A, berechne die Anz. der Zahlen ≤ x
C 0 1 3 3 5
0
1
2
3
4
2) Schreibe jedes x in A direkt an die richtige Position in B
B 0 1 1 3 3 4 4 4
1
2
3
4
5
6
7 8
CountingSort ist stabil!
CountingSort
Plan: 1a) Für jedes x in A, zähle die Anz. der Zahlen gleich x
1b) Für jedes x in A, berechne die Anz. der Zahlen ≤ x
2) Schreibe jedes x in A direkt an die richtige Position in B
Eingabefeld
Ausgabefeld
beschränkt Universum {0, . . . , k }
CountingSort(A, B , k )
sei C [0..k ] = h0, 0, . . . , 0i ein neues Feld
for j = 1 to A.length do C [A[j ]] = C [A[j ]] + 1 // (1a)
// C [i ] enthält jetzt die Anz. der Elem. gleich i in A
for i = 1 to k do C [i ] = C [i ] + C [i − 1]
// (1b)
// C [i ] enthält jetzt die Anz. der Elem. ≤ i in A
for j = A.length downto 1 do
Aufgabe:
B [C [A[j ]]] = A[j ]
// (2)
Fülle die Felder mit Code,
C [A[j ]] = C [A[j ]] − 1
der obige Idee umsetzt!
Laufzeit:
O(n + k )
CountingSort
Plan: 1a) Für jedes x in A, zähle die Anz. der Zahlen gleich x
1b) Für jedes x in A, berechne die Anz. der Zahlen ≤ x
2) Schreibe jedes x in A direkt an die richtige Position in B
Eingabefeld
Ausgabefeld
beschränkt Universum {0, . . . , k }
CountingSort(A, B , k )
sei C [0..k ] = h0, 0, . . . , 0i ein neues Feld
for j = 1 to A.length do C [A[j ]] = C [A[j ]] + 1 // (1a)
// C [i ] enthält jetzt die Anz. der Elem. gleich i in A
for i = 1 to k do C [i ] = C [i ] + C [i − 1]
// (1b)
// C [i ] enthält jetzt die Anz. der Elem. ≤ i in A
for j = A.length downto 1 do
B [C [A[j ]]] = A[j ]
// (2)
C [A[j ]] = C [A[j ]] − 1
RadixSort
(Jahr, Monat, Tag)
Frage: Gegeben Liste von Menschen mit deren Geburtstagen.
Wie würden Sie die Liste nach Alter sortieren?
Drei (?) Lösungen:
Geburtstage in Anz. Tage seit 1.1.1970 umrechnen,
dann vergleichsbasiertes Sortierverfahren verwenden.
Spezielle Vergleichsroutine schreiben und
in vergleichsbasiertes Sortierverfahren einbauen.
Liste 3× sortieren: je 1× nach Jahr, Monat, Tag.
Aber in welcher Reihenfolge??
RadixSort(A, s )
Anz. Stellen (hier: 3)
Laufzeit?
for i = 1 to s do
[1 = Index der niederwertigsten (!) Stelle]
sortiere A stabil nach der i -ten Stelle
z.B. mit CountingSort
BucketSort
[CLRS]
(c) www.seafish.org
Eimerinhalt“: Verkettete Liste von Elementen aus A.
”
Hilfsfeld B [0..n − 1];
jeder Eintrag entspricht einem Eimer“ der Weite 1/n
”
Eingabefeld A[1..n] enthält Zahlen,
Im Bsp. auf 2 Nachzufällig und gleichverteilt aus [0, 1) gezogen
kommastellen gerundet!
[
]
BucketSort
BucketSort(Feld A von Zahlen in [0, 1))
[CLRS]
n = A.length
lege Feld B [0..n − 1] von Listen an
for j = 1 to n do
füge A[j ] in Liste B [bn · A[j ]c] ein
for i = 0 to n − 1 do
sortiere Liste B [i ]
hänge B [0], . . . , B [n − 1] aneinander
kopiere das Ergebnis nach A[1..n]
Korrektheit?
2 Fälle: – A[i ] und A[j ] in der gleichen Liste
Laufzeit?
– A[i ] und A[j ] in verschiedenen Listen
Pn−1
TBS (n) = Θ (n) +
i =0 TIS (ni ),
wobei TIS (·) Laufzeit von InsertionSort
ni ZV für Länge der Liste B [i ]
Erwartete Laufzeit von BucketSort
TBS (n) = Θ (n) +
Pn−1
i =0
TIS (ni ) = Θ (n) +
Pn−1
i =0
O (ni2 )
Pn−1
E [TBS (n)] = E [Θ (n) + i =0 O (ni2 )]
Pn−1
= Θ (n) + i =0 E [O (ni2 )]
Pn−1
= Θ (n) + i =0 O (E [ni2 ]) = Θ (n)
Behauptung: E [ni2 ] ≤ 2 −
1
n
fest!
Beweis. Def. Indikator-ZV Xj := 1, falls A[j ] in Eimer i fällt.
Pn
E [Xj ] = Pr[Xj = 1] = 1/n
⇒ ni = j =1 Xj
P
2 P P
n
n
n
⇒ ni2 =
X
=
j =1 j
j =1
k =1 Xj Xk
Pn
Pn P
2
= j =1 Xj + j =1 k 6=j Xj Xk
Erwartete Laufzeit von BucketSort
Es gilt ni2 =
E [ni2 ]
⇒
=
Pn
2
X
j =1 j +
Pn
2
E
[
X
j ]
j =1
Pn
j =1
+
P
k 6=j
Pn
j =1
Xj Xk
P
k 6=j
Behauptung:
E [ni2 ] ≤ 2 − n1
E [Xj Xk ]
Behandle die beiden Typen von Erwartungswerten getrennt:
unabhängig von j !
E [X 2 ] = 1 · Pr[X 2 = 1] + 0 · Pr[X 2 = 0]
j
j
j
= 1 · Pr[Xj = 1] + 0 · Pr[Xj = 0] = 1 ·
E [Xj ] · E [Xk ] =
E [Xj Xk ] =
1
n
·
1
n
=
1
n2
1
n
+0=
1
n
unabh. von j und k !
für j 6= k sind Xj und Xk unabhängig
Fasse die Zwischenergebnisse zusammen:
Pn
Pn P
2
2
E [ni ] = j =1 E [Xj ] + j =1 k 6=j E [Xj Xk ]
=n·
1
n
+ n · (n − 1) ·
1
n2
= 1+
n−1
n
= 2−
1
n
Zusammenfassung
Jedes vergleichsbasierte Sortierverfahren braucht im
schlechtesten Fall Ω (n log n) Vergleiche für n Zahlen.
CountingSort
sortiert Zahlen in {0, . . . , k } (stabil!)
Laufzeit für n Zahlen: O (n + k )
RadixSort
sortiert s -stellige b -adische Zahlen
Laufzeit für n Zahlen: O (s · (n + b ))
BucketSort
sortiert gleichverteilte zufällige Zahlen
erwartete Laufzeit für n Zahlen: O (n)
Bem.
Die Idee mit den (gleichgroßen) Eimern ist
natürlich nicht nur auf Zufallszahlen beschränkt,
aber hier läßt sie sich hübsch analysieren.
Herunterladen