Document

Werbung
Teil VIII : Ele m e ntare Sortierverfahren
1. Begriffsbestim m u n g
2. Einfache iterative Sortierverfahren
3. Aufwand der einfachen Sortierverfahren
4. Sortieren durch Zerlegen („ Quicksort“)
 K. Murmann, H. Neumann, Fakultät für Informatik, Universität Ulm, 2001
1. B e g riffsbestim m u n g
•
•
Motivation und Einordnung
„Internes Sortieren“ – Schema und Notation
Motivation und Einordnung
Sortieren
Prozeß des Einordnens einer gegebenen Menge von Objekten nach
einem bestimmten Ordnungskriterium
Ziel :
Bsp. : •
Vereinfachung des späteren S u c h e n s nach Elementen der
(dann geordneten) Menge
Telephonbücher
(→ alphabetische Ordnung)
•
Literaturverzeichnisse
(→ alphabetische Ordnung oder nach der Reihenfolge der Zitate)
•
Stichwortverzeichnis / Index in Büchern
(→ alphabetische Ordnung)
•
W ö rterbü cher / Lexika
•
Adreßb ü cher
:
Kategorien von Sortierverfahren
1.
„Internes Sortieren“
Der Datenbestand ist wä hrend des
Sortierens im Hauptspeicher
→ alle Elemente sind zugreifbar
Bsp. :
2.
Sortieren eines Arrays
„ Externes Sortieren“
Der überwiegende Teil des Datenbestands ist
w ä hrend des Sortierens auf Hintergrundspeichern
(Band, Platte)
→ von jedem Bereich (Stapel) sind nur die
obersten Elemente sichtbar
Bsp. :
Hinweis :
Sortieren von sequentiellen
Verzeichnissen (‚Files‘)
Das Problem läßt sich auf das
„interne Sortieren“ zurückführen !
(N. Wirth. Algorithmen und Datenstrukturen. Teubner, 1983)
„Internes Sortieren“ – Schema und Notation
Allgemeines
Sortier-Programm
Unsortierter
Datenbestand
Prinzip :
Datenbestand
im Arbeitsspeicher
Sortierter
Datenbestand
Wirtschaftliche Verwendung des vorhandenen Speichers
⇒ Sortiermethoden, die Elemente am Ort sortieren (!) und
nicht das Feld der Daten duplizieren !
Methoden (Auswahl)
§
Iterative Verfahren
Sortieren durch Auswählen, Einfügen, Austauschen, ...
(„Selection sort“, „Insertion sort“, „Bubble sort“)
§
Rekursive Verfahren
„Quicksort“ – Sortieren durch Zerlegung der Daten in Teile, Sortieren durch Austausch
Notation
geg. : •
n Datensätze der Form
Sortierschlüssel („key“)
Inhalt / Daten
→ Der Sortierschlüssel kann aus einem oder mehreren Teilfeldern bestehen
•
Ordnungsfunktion f
→ ermittelt auf den Schlüsseln eine Ordnungsrelation
Schlüssel
Daten
Bsp. :
S
O
R
I
A
mit
•
•
A
X
T
N
G
M
E
P
A
L
E
Start
Elementgröße (Box) ~ Schlüssel („key“)
Buchstaben / Zeichen ~ Information / Daten
A
E
E
G
I
L
M
N
O
P
R
S
T
X
Ziel
2. Einfache iterative Sortierverfahren
•
•
•
„Selection Sort“ – Direktes Auswählen
„Insertion Sort“ – Direktes Einfügen
„Bubble Sort“ – Direktes Austauschen
„ Selection Sort“ – Direkte Auswahl
Methode
Sortieren durch direktes Auswählen
Start :
§
§
Feld mit N Elementen, arr[1..N]
A u s w a h l eines Elements mit kleinstem Schlüssel
A u s t a u s c h gegen das erste Element im Feld, arr[1]
Wiederholung der Schritte 1 und 2 mit den
•
restlichen N-1 Elementen
•
restlichen N-2 Elementen
:
Hinweis : Die Reihenfolge der Sortierung geschieht von „unten-n a c h -o b e n “ ;
alternativ kann auch von „ o b e n -n a c h -unten“ sortiert werden !
Aktuell kleinstes Element
aus unsortierter Menge
Schema des Algorithmus
1 2
i-1 i
k
N
Vorher :
Bereits endgültig sortiertes Feld
unsortiertes Feld
( ∀j=1..i-2 ): arr[j] ≤ arr[j+1]
k = min( arr[i..N] ) ≥ arr[i-1]
1 2
i-1 i i+1
k
N
Nachher :
Bereits endgültig sortiertes Feld
arr[i] = k
= min‘( arr[i..N] )
arr[i] = max‘( arr[1..i] )
unsortiertes Feld
min‘( arr[(i+1)..N] ) ≥ arr[i]
Jedes Element wird max. 1- mal von höherer (Index-)
Position nach vorn (zur aktuellen Position) bewegt –
und damit endgültig einsortiert !
Beispiel
44
55
12
42
94
18
06
67
i=1:
j = 2 .. 8
44
55
12
42
94
18
06
67
i=2:
j = 3 .. 8
06
55
12
42
94
18
44
67
i=3:
j = 4 .. 8
06
12
55
42
94
18
44
67
i=4:
j = 5 .. 8
06
12
18
42
94
55
44
67
i=5:
j = 6 .. 8
06
12
18
42
94
55
44
67
i=6:
j = 7 .. 8
06
12
18
42
44
55
94
67
i=7:
j = 8 .. 8
06
12
18
42
44
55
94
67
06
12
18
42
44
55
67
94
Ende
Start
Vertauscht mit
sich selbst !
Vertauscht mit
sich selbst !
Sortierte Liste
Algorithmus ‚Selection sort‘
CONST
N =
...;
TYPE
ElemType =
SEQUENCE =
INTEGER;
(* Aufzaehlungstyp ! *)
ARRAY [1..N] OF ElemType;
PROCEDURE SelectMinPosition(
VAR arr
: SEQUENCE;
sortPos : INTEGER): INTEGER;
VAR
j, min :
INTEGER;
BEGIN
min := sortPos;
FOR j := sortPos+1 TO N DO
IF (arr[j] < arr[min]) THEN
min := j
END
END;
RETURN min
END SelectMinPosition;
Merkt sich die Position
min(arr[ sortPos+1 .. N] ) des
unsortierten Teils von arr
Algorithmus ‚Selection sort‘ (cont‘d)
PROCEDURE ExchangeElements(
VAR arr
: SEQUENCE;
pos, minPos : INTEGER);
VAR
buffer :
ElemType;
BEGIN
buffer
:= arr[minPos];
arr[minPos] := arr[pos];
arr[pos]
:= buffer
END ExchangeElements;
buffer
min
PROCEDURE SelectionSort(
VAR arr : SEQUENCE);
VAR
i, pos :
INTEGER;
1
BEGIN
FOR i := 1 TO N-1 DO
pos := SelectMinPosition(arr, i);
ExchangeElements(arr, i, pos)
END
END SelectionSort;
i
N
Bestimme Austauschelemente
M o d u l a -2 P r o g r a m m ‚ SelectionSort‘
„Insertion Sort“ – Direktes Einfügen
Methode
Sortieren durch direktes Einfügen
§
Effizientes Verfahren zur Sortierung
einer kleinen Anzahl von Elementen
§
Analog zum Einfügen von Karten in
einem Kartenspiel (Skat, Bridge,
Rommé, etc.)
Strategie
Die Elemente (Karten) werden begrifflich in eine
•
Ziel-Sequenz
arr[1] ... arr[i-1]
•
aufgeteilt
Quellen-Sequenz
arr[i] ... arr[N]
( Hinweis :
Anzahl der Elemente = N;
i ist variabel = 0 .. N
(Beginn: i = 0, am Ende: i = N))
≡
≡
A, mit |A| = i-1
B, mit |B| = N-(i-1)
(T.H. Cormen, C.E. Leiserson, R.L. Rivest.
Introduction to algorithms. MIT Press, 1990)
Aktuell betrachtetes Element
aus unsortierter Menge
Schema des Algorithmus
1 2
i-1 i
N
Vorher :
Bereits sortiertes Feld,
jedoch noch nicht endgültig !
1 2
k
unsortiertes Feld
| B | = N – (i – 1)
i-1 i i+1
N
Nachher :
Bereits sortiertes Feld
unsortiertes Feld
|A|=i
|B|=N–i
Jedes Element wird max. 1- mal von höherer (Index-)
Position nach vorn (zur aktuellen Position) bewegt – und
damit endgültig einsortiert !
Beispiel
44
55
12
42
94
18
06
67
j=2:
i = 1 .. 1
44
55
12
42
94
18
06
67
i=3:
j = 2 .. 1
44
55
12
42
94
18
06
67
i=4:
j = 3 .. 1
12
44
55
42
94
18
06
67
i=5:
j = 4 .. 1
12
42
44
55
94
18
06
67
i=6:
j = 5 .. 1
12
42
44
55
94
18
06
67
i=7:
j = 6 .. 1
12
18
42
44
55
94
06
67
i=8:
j = 7 .. 1
06
12
18
42
44
55
94
67
06
12
18
42
44
55
67
94
Ende
Start
Sortierte Liste
Algorithmus ‚Insertion sort‘
CONST
N =
...;
TYPE
ElemType =
SEQUENCE =
INTEGER;
(* Aufzaehlungstyp ! *)
ARRAY [1..N] OF ElemType;
PROCEDURE
VAR arr
pos
key
InsertIntoAlreadySortedSequence(
: SEQUENCE;
: INTEGER;
: ElemType);
VAR
halt :
i
:
BOOLEAN;
INTEGER;
BEGIN
i
:= pos – 1;
1
halt := FALSE;
WHILE (NOT halt) AND (arr[i] > key) DO
arr[i+1] := arr[i];
i
:= i – 1;
halt
:= (i = 0)
END;
arr[i+1] := key
END InsertIntoAlreadySortedSequence;
Schlüssel
(„key“)
k
N
Teilsortierter (unterer) Teil wird
von oben nach unten durchlaufen
Einzusortierender Schlüssel
in freie Position
Algorithmus ‚Insertion sort‘ (cont‘d)
PROCEDURE InsertionSort(
VAR arr : SEQUENCE);
VAR
j
:
key :
INTEGER;
ElemType;
N : globale Variable
Alternative : Sequenz ~ ADT
⇒ Fkt. length(arr)
BEGIN
FOR j := 2 TO N DO
key := arr[j];
InsertIntoAlreadySortedSequence(arr, j, key)
END
END InsertSort;
„ Bubble Sort“ – Direktes Austauschen
Methode
Sortieren durch direktes Austauschen
Sortier-Prinzip des fortgesetzten Vergleichens und ggf. Austauschens von Paaren
nebeneinanderliegender Elemente
⇒ Die Elemente können als „ Blasen “ („bubbles“)
aufgefaßt werden, die bei jedem Durchlauf
durch das Feld entsprechend ihres Gewichts
(~ Schlüssel) auf eine entsprechende Höhe
aufsteigen !
In einem Durchlauf können mehrere Blasen
(nacheinander) aufsteigen – bis diese an
einem größeren (~ schwereren) Element
stehenbleiben
z
z
c
u
b
c
a
b
u
a
Schema des Algorithmus
1 2
i-1 i
Vorher :
N
x y
1 2
i-1 i
Nachher :
x y
if x ≤ y
y x
if x > y
Für jeweilige Gesamtdurchläufe durch das Feld :
arr[ N ]
arr[ N-1]
:
arr[ 1 ]
:=
:=
max( arr[ 1..N ] )
max( arr[ 1..(N-1) ] )
:=
arr[ 1 ]
N
Beispiel
44
55
12
42
94
18
06
67
i=8:
j = 2 .. 8
44
12
42
55
18
06
67
94
i=7:
j = 2 .. 7
12
42
44
18
06
55
67
94
i=6:
j = 2 .. 6
12
42
18
06
44
55
67
94
i=5:
j = 2 .. 5
12
18
06
42
44
55
67
94
i=4:
j = 2 .. 4
12
06
18
42
44
55
67
94
i=3:
j = 2 .. 3
06
12
18
42
44
55
67
94
i=2:
j = 2 .. 2
06
12
18
42
44
55
67
94
06
12
18
42
44
55
67
94
Ende
Start
Sortierte Liste
Algorithmus ‚Bubble sort‘
CONST
N =
...;
TYPE
ElemType =
SEQUENCE =
INTEGER;
(* Aufzaehlungstyp ! *)
ARRAY [1..N] OF ElemType;
PROCEDURE BubbleSort(
VAR arr : SEQUENCE);
VAR
i, j :
i
1 2
bereits sortiert
i
INTEGER;
? ? ?
BEGIN
j
FOR i := N TO 1 BY –1 DO
FOR j := 2 TO i DO
Aufsteigen der „Blasen“
(* -- Austausch wie in SelectionSort *)
ExchangeElements(arr, j-1, j)
END
END
END BubbleSort;
N
V e r b e s s e r u n g e n v o n „ Bubble sort“
1.
Termination
Man merkt sich, ob es während des Durchlaufs eine Vertauschung gegeben hat
keine Vertauschung
2.
⇒ Termination
Symmetrie
schwereren
bisher : Asymmetrie im Aufsteigen der „Blasen“ im
Ende des Feldes
leichteren
Bsp. :
12
18
42
44
55
76
94
06
1
2
3
4
5
6
7
Lösungsansatz :
Änderung der Richtung
aufeinanderfolgender Durchläufe !
Aufsteigend – absteigend –
aufsteigend – etc.
→ „ Shaker sort“
94
1
06
12
18
42
44
55
67
(N. Wirth. Algorithmus und
Datenstrukturen. Teubner, 1983, p.87)
3. A u f w a n d d e r einfachen Sortierverfahren
•
•
Allgemeine Analyse der Ausführungszeiten
Aufwand von „Selection sort“
Allgemeine Analyse der Ausführungszeiten
Einordnung
Ausführungszeit eines Programms
=
f( Größe +
Struktur der Eingabedatenmenge )
Anzahl primitiver Operationen („Schritte“)
Anzahl der Elemente
(→ möglichst maschinenunabhängig)
z.B.
§
Erste Näherung :
konst. Zeitbedarf für die Ausführung einer
Kommandozeile (z.B. in Pseudocode)
§
Betrachtung von
- Vergleichsoperationen (Tests)
- Vertauschungen, Zuweisungen
:
und
- Lä nge eines Feldes n
- Knoten und Kanten (Graphen)
D e r A u f w a n d f ü r „ Selection / Insertion / Bubble sort“
Allgemeine Betrachtung der notwendigen Anzahl von Operationen
§
„ Selection sort“
Struktur :
•
•
( )
f (n ) ∝ (n − 1) ⋅ (c ⋅ n ) = O n 2
Aufwand :
§
„Insertion sort“
Struktur :
•
•
Feld ‚arr‘ wird von 2 .. N durchlaufen
jedesmal wird von der aktuellen Position das Feld nach unten durchlaufen,
um das aktuelle Element an der richtigen Stelle einzusortieren
( )
f (n ) ∝ (n − 1) ⋅ (c ⋅ n ) = O n 2
Aufwand :
§
Feld ‚arr‘ wird von 1 .. N-1 durchlaufen
jedesmal wird das Feld zur Bestimmung des min. Elements von der
aktuellen Position bis zum Ende durchlaufen
„ Bubble sort“
Struktur :
Aufwand :
•
•
Feld ‚arr‘ wird von N .. 1 durchlaufen
jedesmal wird von 2 .. aktueller Position das Feld durchlaufen und dabei
ggf. zwei nebeneinanderliegende Elemente miteinander vertauscht
( )
f (n ) ∝ n ⋅ (c ⋅ n ) = O n 2
A u f w a n d v o n „ Selection sort“
Struktur – Algorithmus
Hinweis :
Zusammenfassung aller Unterprogramme, so daß der ganze Sortieralgorithmus
als eines Unterprogramm geschrieben wird
Kosten
Anzahl
PROCEDURE SelectionSort(VAR arr :
VAR
i, min :
buffer :
SEQUENCE);
INTEGER;
ElemType;
BEGIN
1 FOR i := 1 TO N-1 DO
2
(* -- bestimme Pos. des min. Elements *)
3
min := i;
4
FOR j := i + 1 TO N DO
5
IF ( arr[j] < arr[min] ) THEN
6
min := j
END
END;
7
(* -- vertausche Element *)
8
buffer
:= arr[min];
9
arr[min] := arr[i];
10
arr[i]
:= buffer
END
END SelectionSort;
c1
0
c3
c4
c5
c6
(*)
N
N − 1 (*)
N −1
N (N + 1) / 2 − 1 (**)
N (N N−−11) / 2 (**)
∑i=1 ti
0
N −1
c8
c9
c10
N −1
N −1
N −1
Analyse der Schritte
(*)
bei k Durchläufen stets k+1 Tests !
(**)
i
j
Durchläufe ( 5 )
Tests ( 4 )
(Durchläufe + 1)
N −1
1
2K N
N −1
N
2
3K N
N −2
N −1
3
4K N
N −3
N −2
M
M
M
M
N −1
NKN
N − ( N − 1) = 1
2
N
(N + 1) − N = N (N − 1)
2
2
N (N − 1)
N (N + 1)
+ (N − 1) =
−1
2
2
Ausführungszeit
Ausführungszeit des Algorithmus
=
S u m m e d e r Zeiten für jede ausgeführte
Anweisung
T (n ) = c1n + c3 (n − 1) + c4 

n(n + 1) 
n(n − 1)
− 1 + c5
+
2
2

n −1
c6 ∑ ti + c8 (n − 1) + c9 (n − 1) + c10 (n − 1)
i =1
die definierte Ausführungszeit des Algorithmus hängt von der
Strukturierung der Daten ab !
Wichtig : hier ist die kritische Stelle die Anzahl der Änderungen
(„updates“) von
min in
Kommandozeile 6 !
Analyse
1.
B e d i n g u n g d e s geringsten A u f w a n d s
Feld ist bereits sortiert !
(∀j = (i + 1)K n ) : arr[i ] ≤ arr[ j ]
(in Zeile 5 )
⇒ ti = 0
(in Zeile 6 )
n(n − 1)
 n(n + 1) 
(
)
T
n
=
(
)
c
n
+
c
n
−
1
+
c
−
1
+
c
+
⇒
 5
1
3
4
2
 2

c6 0 + c8 (n − 1) + c9 (n − 1) + c10 (n − 1)
a
→ T (n )
1
c4 c5


2
(
)
c
+
c
n
+
c
+
c
+
−
+
c
+
c
+
c
 1 3
=
4
5
8
9
10 n
2
2 2


− (c3 + c4 + c8 + c9 + c10 )
b
c
ist eine quadratische Funktion von n,
an 2 + bn + c
!
2.
B e d i n g u n g d e s größten A u f w a n d s
Feld ist in umgekehrter (absteigender) Ordnung sortiert !
X
T
S
R
P
O
N
M
L
I
G
E
E
A
1
A
n
⇒ jedes Element arr[ i ] muß mit jedem Element des restlichen Feldes
arr[ (i+1)..n ] verglichen und mit einem vertauscht werden !
Wie oft wird ein „update“ von
min durchgeführt ?
X
T
S
R
P
O
N
M
L
I
G
E
E
A
1
A
n
Start-Zustand
P
A
A
E
E
O
N
M
R
L
I
S
T
G
1
ZwischenErgebnis
X
n
(i − 1)
n
2
(i − 1)
n − (i − 1) = n − i + 1
d.h. für

 ∀j = (i + 1) ≤


 ∀j = (i + 1) >


 : (n − 2(i − 1)) − mal

n
 : 0 − mal
2
n
2
⇒ ti = n − 2( j − 2 )
= n − 2(i − 1) = n − 2i + 2
so daß
und
für j = 2, 3, .., n/2
( da j = i+1 )
n/2
n/2
n/ 2
i =1
i =1
i =1
∑ (n − 2i + 2) = ∑ (n + 2) − 2∑ i
=
n
n

3
n
+
+


2
2 
=
3 n 
n + 1
2 2 
n
(n + 2 )
2
nn 
2  + 1
42 
nn 
=  + 1
22 
⇒ T (n ) = c n + c (n − 1) + c  n(n + 1) − 1 + c n(n − 1) +
1
3
4
5
2
2


3 n 
c6 n + 1 + c8 (n − 1) + c9 (n − 1) + c10 (n − 1)
2 2 
a‘
wie vorher !
wie vorher !
1
3  2 
c4 c5 3c6

+
+
+
+
+
−
+
+
+
+
c
c
c
n
c
c
c
c
c
 1 3
=  4 5
6
8
9
10 n
2
2 
2 2
2


− (c3 + c4 + c8 + c9 + c10 )
b‘
c‘
→ T (n )
a ' n 2 + b' n + c '
ist eine quadratische Funktion von n,
wobei
3
a ' = a + c6
2
,
3
b ' = b + c6
2
,
c' = c
!
3.
Mittlerer Aufwand
Die n Elemente des Feldes sind zufällig angeordnet !
S
A
O
R
X
T
I
N
G
E
M
P
A
1
L
E
n
⇒ Wie aufwendig ist die Bestimmung des neuen Elements arr[ i ] , d.h.
Wie groß ist die Anzahl der „updates“ von
min ?
intuitive Herangehensweise :
50% in arr[ (j+1) .. n ] kleiner als arr[ i ]
im Mittel sind
50% in arr[ (j+1) .. n ] größer als arr[ i ]
in der Hälfte aller Fälle ist arr[ j ] < arr[ min ]
⇒ ti = n − i + 1
2
n
n − i + 1 n(n + 1)
so daß ∑
=
2
4
i =1
wie vorher !
n(n − 1)
 n(n + 1) 
⇒ T (n ) = c1n + c3 (n − 1) + c4 
− 1 + c5
+
2
 2

n(n + 1)
+ c8 (n − 1) + c9 (n − 1) + c10 (n − 1)
c6
4
→ T (n )
ist eine quadratische Funktion von n,
an 2 + bn + c
wie vorher !
!
Resultat – A u f w a n d v o n „ Selection sort“
O(n 2 )
1.
Der A u f w a n d für „ Selection sort“ ist von der Art
, also quadratisch !
2.
Der Aufwand ist gleich hoch, unabhängig von der Anordnung der Elemente
der zu sortierenden Menge !
∴ Der einzige Programmteil, der von der Struktur der Eingabe abhängt, ist die
Anzahl der Neubestimmungen für
min (Programm-Zeile
6) !
→ Wiederholung und Test werden unabhängig davon immer O(n 2 )- mal
ausgeführt !
Verfeinerung
Bisher :
alle Operationen (Kommandozeilen) wurden mit individuellen Kosten c i
abgerechnet
Weiterführung : etwas detailliertere Aussage
-
Wieviele Vergleichs- Operationen (Tests) ?
-
Wieviele D a t e n a u s t a u s c h - Operationen (Zustandsänderungen) ?
⇒ Festlegung eines abstrakten Maschinenmodells mit bestimmtem Befehls-Umfang, von
denen jeder Befehl mit einem bestimmten Einheits- K o s t e n m a ß berechnet wird !
4. Sortieren durch Zerlegen („Quicksort“)
•
•
•
Struktur des Ansatzes
Quicksort – Wahl des Pivots und Algorithmus
Aufwand für „Quicksort“
Struktur des Ansatzes
Defizite der einfachen Verfahren
Jedes zu sortierende Element wird stets mit direkt benachbarten Elementen
verglichen – und danach mit wiederum benachbarten Elementen. Dadurch
benötigen die auf einfachen Vergleichsstrategien beruhenden Verfahren stets
einen A u f w a n d v o n O ( n 2 ) !
Grundidee für eine Alternative
Effizientes Sortieren durch Austauschen weit voneinander
entfernt gelegener Elemente !
Bsp. : Absteigend geordnete Liste soll aufsteigend geordnet werden !
⇒ vertausche
vertausche
vertausche
etc.
1↔n,
2 ↔ (n-1) ,
3 ↔ (n-2) ,
Benötigt jedoch a priori Kenntnis über die
Struktur (Anordnung der Daten) !
Strukturierung
links
rechts
→ „Teile-und-Herrsche“ Paradigma
1.
„Teile“ (Zerlegung und Umordnung der Elemente)
l
Feld :
r
A[l K r ]
l
A[l K q ]
⇒
q q+1
q
q+1
A[(q + 1)K r ]
(∀i ∈ [l K q ], j ∈ [(q + 1)K r ]) : A[i ] ≤ A[ j ]
Index q wird im Rahmen der Zerlegung bestimmt !
Hinweis : Die Werte innerhalb der Teilbereiche sind nicht geordnet !
r
2.
„Herrsche“
[
Die Teilfelder A l K q
Teilen sortiert !
3.
]
und
A[(q + 1)K r ]
werden weiter (rekursiv) durch
Zusammenfügen (Kombination)
→ kein weiterer Aufwand nötig
Die Teilfelder sind bereits sortiert
Das gesamte Feld
A[l K r ]
ist sortiert !
Organisation der Zerlegung :
1.
Auswahl eines Elements, „ key “, aus den Elementen
„ key “
2.
(~ Pivot) : Sortierung aller Elemente bzgl. dieses Vergleichs-Elementes !
l
i
j
r
Aufbau zweier (Teil-) Regionen :
arr
Region
B :
C :
(∀x ∈ arr[l Ki ]) : x ≤ key
(∀y ∈ arr[ j K r ]) : y ≥ key
B
C
⇒
arr [i ] ≤ key ≤ arr [ j ]
Start : Feld mit Elementen l .. r
Auswahl des Pivot-Elements
§
Paare von Elementen
arr[i ] ≤ key
arr [ j ] ≥ key
arr [i ]
und
arr [ j ] ,
die jeweils die Bedingungen
bzw.
verletzen , werden vertauscht („exchange“) !
key
l
arr[i]
arr[j]
r
Exchange
§
Wiederholung solange, bis i und j sich treffen , d.h.
i≥ j
Bedingung definiert den Zerlegungspunkt
q
Quicksort – Wahl des Pivots und Algorithm u s
W a h l d e s Pivots („k e y “) für ein (Teil-) Feld arr[l..r]
Naiver Ansatz :
W ä hle ein Element zufällig aus !
key
l
r
max(arr [l K r ]) = arr [r ]
Problem :
key := arr [r ]
⇒
und
Es werden keine Elemente vertauscht und
der Zerlegungspunkt wird q = r
~ Endlosschleife !
Alternative :
W ä hle das erste Element als Pivot, d.h.
key := arr [l ]
1
Beispiel
i=0, j=9
key = arr[1] = 44
44
8
44
55
12
42
94
18
06
67
44
55
12
42
94
18
06
67
i
i=1, j=7
Start
j
arr [1] ≥ key 44
i=2, j=6
arr [2] ≥ key
06
55
i=5, j=4
i≥ j
06
18
12
18
12
42
42
94
06
67
arr [7] ≤ key
18
44
67
arr [6] ≤ key
55
44
67
94
55
44
Stop
06
Weiter ...
67
Beispiel (cont‘d)
1
i=0, j=4
key = arr[1] = 06
06
4
06
18
12
42
06
18
12
42
i
i=1, j=1
arr [1] ≥ key 06
j
18
12
42
arr [1] ≤ key
18
12
42
i≥ j
Stop
06
Weiter ...
Beispiel (cont‘d)
1
i=0, j=3
key = arr[1] = 18
18
3
18
12
42
18
12
42
i
j
i=1, j=2
arr [1] ≥ key 18
12
42 arr [2] ≤ key
i=2, j=2
arr [1] ≥ key 12
18
42 arr [2] ≤ key
i≥ j
Stop
usw. ...
06
18
42
Algorithmus ‚Quicksort‘
CONST
N =
...;
TYPE
ElemType =
SEQUENCE =
INTEGER;
(* Aufzaehlungstyp ! *)
ARRAY [1..N] OF ElemType;
(* -- initialer Aufruf: QuickSort(arr, 1, N) *)
PROCEDURE QuickSort(
VAR arr
: SEQUENCE;
left, right : INTEGER);
VAR
q :
N = Länge von ‚arr‘
INTEGER;
BEGIN
IF (left < right) THEN
q := Partition(arr, left, right); (* -- zentraler Teil ... *)
QuickSort(arr, left, q);
QuickSort(arr, q+1, right)
END
END QuickSort;
Algorithmus ‚Quicksort‘ (cont‘d)
PROCEDURE Partition(
VAR arr
: SEQUENCE;
left, right : INTEGER): INTEGER;
VAR
i, j :
key :
INTEGER;
ElemType;
BEGIN
key :=
i
:=
j
:=
arr[left];
left – 1;
right + 1;
Zur Sortierung in aufsteigender Reihenfolge wird als ‚key‘ das 1.
Feldelement gewählt, um mögliche Endlosschleifen zu verhindern !
WHILE (i < j) DO
REPEAT
Hier: Annehmende Schleifen ...
i := i + 1
Abweisende Schleifen mit WHILE ... benötigen hier
UNTIL (arr[i] >= key);
zusätzlichen Aufwand für INCR(i) und DECR(j)
REPEAT
j := j - 1
UNTIL (arr[j] <= key);
IF (i < j) THEN
ExchangeElements(arr, i, j)
END;
RETURN j (* Trennpunkt fuer Rekursion*)
END Partition;
M o d u l a -2 P r o g r a m m ‚ QuickSort‘
A u f w a n d v o n „ Quicksort“
Allgemeine Bewertung
→ Die Laufzeit hängt davon ab, ob die Zerlegung balanciert oder unbalanciert ist ! Letzteres
hängt wiederum von der Wahl des Pivot-Elements „key“ ab !
Laufzeiten
1.
Schlechte Zerlegung
Zerlegung :
1
1
2
n
(n-1)
Annahme :
unbalancierte Zerlegung tritt bei jedem Schritt auf,
z.B. bei bereits vollständig sortierter Sequenz !
Kosten :
Zerlegung kostet O(n) und T(1) = O(1)
Bezeichnet die Rekursion
Rekursion für die Ausführung von ‚Quicksort‘ :
T (n ) = T (n − 1) + O (n )
(mit
T (1) = O(1) )
n
= ∑ O(k )
n
k =1
 n 
= O ∑ k 
 k =1 
= O n2
n −1
1
( )
n
n−2
1
n
n
n −1
n−3
1
n−2
M
1
2
1
Resultat : Die Zeitkomplexität
ist im ungünstigsten Fall O(n 2 ) –
dann, wenn die Eingabesequenz bereits vollständig sortiert ist !
3
1
2
( )
O n2
2.
Beste Zerlegung
Zerlegung :
1
n
n/2
n/2
Rekursion für die
Ausführung von
‚Quicksort‘ :
n
n
T (n ) = 2T   + O(n )
2
= O(n ⋅ log 2 n ) log 2 n
n
n/2
n/4
n
n/2
n/4
n /8 n /8 n /8 n /8
n/4
n/4
n
n /8 n /8 n /8 n /8
M
1 1 1 1 1 1 1 1 1 1 1 1 1 1
n
O (n ⋅ log 2 n )
3.
Balancierte Zerlegung (mittlerer Aufwand)
Beispiel-Zerlegung (9:1) :
1
n
9/10 n
1/10 n
Rekursion für die Ausführung von ‚Quicksort‘ :
9 
1 
T (n ) = T  n  + T  n  + O(n )
 10 
 10 
Analyse / Erläuterungen :
q Für jede Ebene trägt der Zerlegungsbaum die Kosten n bei,
bis die Blätter der Ebene log10n = O(log2n) erreicht sind
q Die weiteren Ebenen haben geringere Kosten n;
der Baum terminiert bei einer Tiefe von log10/9n = O(log2n)
n
log10 n
log10 / 9 n
n
1
n
10
1
n
100
9
n
10
9
n
100
9
n
100
1
n
81
n
100
81
n
1000
n
729
n
1000
n
≤n
1
≤n
O (n ⋅ log 2 n )
Resumee :
()
(
)
Der Aufwand ist T n = O n ⋅ log 2 n (gilt z.B. auch für 99:1) !
Damit ist im Mittel der Aufwand von ähnlicher Größenordnung wie für die beste
Zerlegung !
§
Sortierverfahren sind von zentraler Bedeutung für die Informatik, da hiermit Daten
in eine Ordnung gebracht werden, mit der anschließend effektiv gesucht werden
kann ( → Suchverfahren ); die Elemente der unsortierten Datenmenge werden a m
Ort sortiert !
§
Die zu sortierenden Datensätze bestehen aus Sortierschlüsseln („k e y s “) und
den eigentlichen Inhalten (Daten) ; die Ordnung aufgrund der Sortierung geschieht
nach dem (den) verwendeten Sortierschlüssel(n)
§
Einfache iterative Sortierverfahren wurden vorgestellt, die auf jeweils
unterschiedlichen Sortierstrategien beruhen:
• Sortieren durch direkte Auswahl („ Selection sort “),
• Sortieren durch direktes Einfügen („ Insertion sort “) und
• Sortieren durch direktes Austauschen („ Bubble sort “)
Alle Verfahren haben einen B e r e c h n u n g s a u f w a n d (Zeitkomplexität) der Art O(n 2 )
– für eine gegebene Anzahl von Datenelementen n – was auf den sukzessive
paarweisen Vergleich benachbarter Elemente in der Sequenz zurückzuführen ist;
für den Algorithmus „Selection sort“ wurden detailliert die Fälle des geringsten,
größten sowie des mittleren Aufwands analysiert – alle resultieren in O(n 2 )
§
„ Quicksort “ arbeitet rekursiv – nach dem „divide-and-conquer“ Prinzip – wobei die
Daten jeweils in Teilmengen mit kleinen bzw. großen Schlüsseln zerlegt werden;
die Analyse der Zeitkomplexität resultiert für den allgemeinen Fall in einem
Aufwand von O(n·log 2 n) – nur im (seltenen )Falle einer komplett sortierten Liste ist
der Aufwand O(n 2 )
Herunterladen