n - DCC

Werbung
Kapitel 6: Suchbäume und weitere
Sortierverfahren
6.1 Binäre Bäume
Die Klasse BinTree mit Traversierungsmethoden
6.2 Suchbäume
6.2.1 AVL Bäume
6.3 HeapSort und BucketSort
6.3.1 HeapSort
6.3.2 BucketSort
1
6.3 BucketSort
Alle Sortierverfahren bisher basieren auf:
Vergleiche je zweier Schlüssel.
Allgemeine untere Schranke für den Aufwand:
O(n log n).
Für spezielle Schlüsselmengen:
Sortieren möglich ohne Vergleiche und effizienter!
2
Idee: verwende die Schlüssel zur Berechnung der
Speicheradresse in der sortierten Folge (wie beim
Hashing).
Beispiel:
Menge von n Datenobjekten {s0, ... , sn-1} mit
Schlüsselwerten 0, ..., n-1, gegeben als Array S.
Sortieralgorithmus:
for(int i = 0, i < n, i++)
T[S[i].key] = S[i];
Aufwand: O(n).
3
Menge von n Datenobjekten {s0, ... , sn-1} mit Schlüsselwerten 0,
..., m-1, gegeben als Array S.
Duplikate zugelassen.
Erinnerung:
CountingSort (Aufgabe 19)
{int C[] = new int[k];
for(int j = 0, j < m, j++) C[j] = 0;
for(int i = 0, i < n, i++) C[S[i].key]++;
for(int j = 0, j < m, j++) C[j] = C[j]+C[j-1];
for(int i = n-1, i >= 0, i++) {
T[C[S[i].key]-1] := S[i];
C[S[i].key]--; } }
Aufwand: O(n+m).
4
BucketSort
Menge von n Datenobjekten {s0, ... , s n-1} mit Schlüsselwerten
0, ..., m-1, gegeben als Array S.
Duplikate zugelassen.
void BucketSort(S) {
int i; int j;
for(j=0; j<m; j++) B[j] = null;
for(i=0; i<n; i++)
insert(S[i], B[S[i].key()] );
for(j=0; j<m; j++) output(B[j]);
}
Aufwand: O(n+m).
5
RadixSort
Menge von n Datenobjekten {s0, ... , sn-1} mit
Schlüsselwerten 0, ..., nk -1, gegeben als Array S.
Duplikate zugelassen.
Bucketsort dafür: O(n + nk).
Verbesserung (RadixSort):
• schreibe die Schlüssel zur Basis n. Man erhält Zahlen
mit k Ziffern.
• Sortiere der Reihe nach (z.B. von hinten mittels mod und
div) nach jeder Ziffer mit BucketSort.
Aufwand: O(k•n).
6
Beispiel zu RadixSort:
n=10, k=2.
Zu sortierende Folge:
64, 17, 3, 99, 79, 78, 19, 13, 67, 34.
1. Schritt: Einfügen in Buckets nach letzter Ziffer:
0
1
2
3
4
5
6
3 64
13 34
7
8
9
17 78 99
67
79
19
und (von oben) ausgeben:
3, 13, 64, 34, 17, 67, 78, 99, 79, 19
7
Fortsetzung RadixSort
2. Schritt: im 1. Schritt ausgegebene Folge
3, 13, 64, 34, 17, 67, 78, 99, 79, 19
einfügen in Buckets nach vorletzter Ziffer:
0
1
3
13
17
19
2
3
34
4
5
6
7
64 78
67 79
8
9
99
und ausgeben:
3, 13, 17, 19, 34, 64, 67, 78, 79, 99.
8
Verallgemeinerung:
Ziffern können an den verschiedenen Positionen
auch in verschiedenen Wertebereichen liegen.
Beispiel: Datum=(Jahr, Monat, Tag)
( [0..9999], [1..12], [1..31] )
BucketSort nach Jahr, nach Monat und nach Tag.
9
Kapitel 7: Ausgewählte Algorithmen
7.1 Externes Suchen
10
7.1 Externes Suchen
• Bisherige Algorithmen: geeignet, wenn alle
Daten im Hauptspeicher.
• Große Datenmengen: oft auf externen
Speichermedien, z.B. Festplatte.
Zugriff: immer gleich auf einen ganzen Block
(eine Seite) von Daten, z.B: 4096 Bytes.
Effizienz: Zahl der Seitenzugriffe klein halten!
11
Für externes Suchen: Variante von Suchbäumen
mit:
Knoten = Seite
Vielwegsuchbäume!
12
Definition (Vielweg-Suchbaum)
Der leere Baum ist ein Vielweg-Suchbaum mit der
Schlüsselmenge {}.
Seien T0, ..., Tn Vielweg-Suchbäume mit Schlüsseln aus einer
gemeinsamen Schlüsselmenge S, und sei k1,...,kn eine
Folge von Schlüsseln mit k1 < ...< kn. Dann ist die Folge
T0 k1 T1 k2 T2 k3 .... kn Tn
ein Vielweg-Suchbaum genau dann, wenn:
• für alle Schlüssel x aus T0 gilt: x < k1
• für i=1,...,n-1, für alle Schlüssel x in Ti gilt: ki < x < ki+1,
• für alle Schlüssel x aus Tn gilt: kn < x .
13
B-Baum
Definition 7.1.2
Ein B-Baum der Ordnung m ist ein Vielweg-Suchbaum mit
folgenden Eigenschaften
• 1  #(Schlüssel in Wurzel)  2m
und
m  #(Schlüssel in Knoten)  2m
für alle anderen Knoten.
• Alle Pfade von der Wurzel zu einem Blatt sind gleichlang.
• Jeder innere Knoten mit s Schlüsseln hat genau s+1
Söhne.
14
Beispiel: Ein B-Baum der Ordnung 2:
15
Abschätzungen zu B-Bäumen
Ein minimal gefüllter B-Baum der Ordnung m und Höhe h:
• Knotenzahl im linken wie im rechten Teilbaum
1 + (m+1) + (m+1)2 + .... + (m+1)h-1
= ( (m+1)h – 1) / m.
Die Wurzel hat einen Schlüssel, alle anderen Knoten
haben m Schlüssel.
Insgesamt: Schlüsselzahl n in einem B-Baum der Höhe h:
n  2 (m+1)h – 1
Also gilt für jeden B-Baum der Höhe h mit n Schlüsseln:
h  logm+1 ((n+1)/2) .
16
Beispiel
Also gilt für jeden B-Baum der Höhe h mit n Schlüsseln:
h  logm+1 ((n+1)/2).
Beispiel: Bei
• Seitengröße: 1 KByte und
• jeder Eintrag nebst Zeiger: 8 Byte,
kann m=63 gewählt werden, und bei
• einer Datenmenge von n= 1000 000
folgt
h  log 64 500 000.5 < 4 und damit hmax = 3.
17
7.1 Externes Suchen
Definition 7.1.2
Ein B-Baum der Ordnung m ist ein Vielweg-Suchbaum mit
folgenden Eigenschaften
• 1  #(Schlüssel in Wurzel)  2m
und
m  #(Schlüssel in Knoten)  2m
für alle anderen Knoten.
• Alle Pfade von der Wurzel zu einem Blatt sind gleichlang.
• Jeder innere Knoten mit s Schlüsseln hat genau s+1
Söhne.
18
Beispiel: Ein B-Baum der Ordnung 2:
19
Abschätzungen zu B-Bäumen
Ein minimal gefüllter B-Baum der Ordnung m und Höhe h:
• Knotenzahl im linken wie im rechten Teilbaum
1 + (m+1) + (m+1)2 + .... + (m+1)h-1
= ( (m+1)h – 1) / m.
Die Wurzel hat einen Schlüssel, alle anderen Knoten
haben m Schlüssel.
Insgesamt: Schlüsselzahl n in einem B-Baum der Höhe h:
n  2 (m+1)h – 1
Also gilt für jeden B-Baum der Höhe h mit n Schlüsseln:
h  logm+1 ((n+1)/2) .
20
Beispiel
Also gilt für jeden B-Baum der Höhe h mit n Schlüsseln:
h  logm+1 ((n+1)/2).
Beispiel: Bei
• Seitengröße: 1 KByte und
• jeder Eintrag nebst Zeiger: 8 Byte,
kann m=63 gewählt werden, und bei
• einer Datenmenge von n= 1000 000
folgt
h  log 64 500 000.5 < 4 und damit hmax = 3.
21
Algorithmen zum Einfügen und Löschen
von Schlüsseln in B-Bäumen
Algorithmus insert (root, x)
//füge Schlüssel x in den Baum mit Wurzelknoten root ein
suche nach x im Baum mit Wurzel root;
wenn x nicht gefunden
{ sei p Blatt, an dem die Suche endete;
füge x an der richtigen Position ein;
wenn p nun 2m+1 Schlüssel
{overflow(p)}
}
22
Algorithmus Split (1)
Algorithmus overflow (p) =
split (p)
Algorithmus split (p)
Erster Fall: p hat einen
Vater q.
Zerlege den übervollen
Knoten. Der mittlere
Schlüssel wandert in den
Vater.
Anmerkung: das Splitting
muss evtl. bis zur Wurzel
wiederholt werden.
23
Algorithmus Split (2)
Algorithmus split (p)
Zweiter Fall: p ist
die Wurzel.
Zerlege den
übervollen Knoten.
Eröffne eine neue
Ebene nach oben
mit einer neuen
Wurzel mit dem
mittleren Schlüssel.
24
Algorithmus delete (root ,x)
//entferne Schlüssel x aus dem Baum mit Wurzel root
suche nach x im Baum mit Wurzel root;
wenn x gefunden
{ wenn x in einem inneren Knoten liegt
{ vertausche x mit dem nächstgrößeren
Schlüssel x' im Baum
// wenn x in einem inneren Knoten liegt, gibt
// es einen nächstgrößeren Schlüssel
// im Baum, und dieser liegt in einem Blatt
}
sei p das Blatt, das x enthält;
lösche x aus p;
wenn p nicht die wurzel ist
{ wenn p m-1 Schlüssel hat
{underflow (p)} } }
25
Algorithmus underflow (p)
// behandle die Unterläufe des Knoten p
wenn p einen Nachbarknoten hat mit s>m Knoten
{ balance (p,p') }
anderenfalls
// da p nicht die Wurzel sein kann, muss p Nachbarn mit
m Schlüsseln haben
{ sei p' Nachbar mit m Schlüsseln; merge (p,p')}
26
Algorithmus balance (p, p')
// balanciere Knoten p mit seinem Nachbarknoten p'
(s > m , r = (m+s)/2 -m )
27
Algorithmus merge (p,p')
// verschmelze Knoten p mit seinem Nachbarknoten
Führe die folgende Operation durch:
Anschließend:
wenn ( q <> Wurzel)
und (q hat m-1
Schlüssel)
underflow (q)
anderenfalls (wenn
(q= Wurzel) und
(q leer)) {gib q frei
und lasse root auf
p^ zeigen}
28
Rekursion
Wenn es bei underflow zu merge kommt, muss
evtl. underflow eine Ebene höher wiederholt
werden.
Dies kann sich bis zur Wurzel fortsetzen.
29
Beispiel:
B-Baum der
Ordnung 2
30
Aufwand
Sei m die Ordnung des B-Baums,
n die Zahl der Schlüssel.
Aufwand für Suchen, Einfügen, Entfernen:
O(h) = O(logm+1 ((n+1)/2) )
= O(logm+1(n)).
31
Anmerkung:
B-Bäume auch als interne Speicherstruktur zu
gebrauchen:
Besonders: B-Bäume der Ordnung 1
(dann nur 1 oder 2 Schlüssel pro Knoten –
keine aufwändige Suche innerhalb von Knoten).
Aufwand für Suchen, Einfügen, Löschen:
O(log n).
32
Anmerkung: Speicherplatzausnutzung:
über 50%
Grund: die Bedingung:
1/2•k  #(Schlüssel in Knoten)  k
Für Knoten  Wurzel
(k=2m)
33
Noch höhere Speicherplatzausnutzung möglich,
z.B. über 66% mit Bedingung:
2/3•k  #(Schlüssel in Knoten)  k
für alle Knoten mit Ausnahme der Wurzel und ihrer
Kinder.
Erreichbar durch 1) modifiziertes Balancieren auch
beim Einfügen und 2) split erst, wenn zwei
Nachbarn ganz voll.
Nachteil: Häufigere Reorganisation beim Einfügen
und Löschen notwendig.
34
7.2 Externes Sortieren
Problem: Sortieren großer Datenmengen, wie
beim Externen Suchen gespeichert in Blöcken
(Seiten).
Effizienz: Zahl der Seitenzugriffe klein halten!
Strategie: Sortieralgorithmus, der Daten
sequentiell verarbeitet (kein häufiges Wechseln
der Seiten): MergeSort!
35
Beginn: n Datensätze in einem File g1,
unterteilt in Seiten der Größe b:
Seite 1: s1,…,sb
Seite 2: sb+1,…s2b
…
Seite k: s(k-1)b+1 ,…,sn
( k = [n/b]+ )
Bei sequentieller Verarbeitung: nur k Seitenzugriffe
statt n.
36
Varianten von MergeSort für Externes Sortieren
MergeSort: Divide-and-Conquer-Algorithmus
Für Externes Sortieren: ohne Divide-Schritt,
nur noch Merge.
Definition: Lauf := geordnete Teilfolge innerhalb
eines Files.
Strategie: durch Merge immer größere Läufe
erzeugen, bis alles sortiert.
37
Algorithmus
1. Schritt: Erzeuge aus der Folge im Eingabefile g1
„Anfangsläufe“ und verteile sie auf zwei Files f1
und f2,
gleich viele (1) auf jeden.
(hierzu gibt es verschiedene Strategien, später).
Nun: verwende vier Files f1, f2, g1, g2.
38
2. Schritt (Hauptschritt):
Solange Zahl der Läufe > 1 wiederhole: {
• Mische je zwei Läufe von f1 und f2 zu einem
doppelt so langen Lauf abwechselnd nach g1
und g2, bis keine Läufe auf f1 und f2 mehr übrig.
• Mische je zwei Läufe von g1 und g2 zu einem
doppelt so langen Lauf abwechselnd nach f1 und
f2, bis keine Läufe auf g1 und g2 mehr übrig.
}
Jede Schleife = zwei Phasen
39
Herunterladen