Ein digitaler Suchbaum A S X L M N I H G C E P R 0 0 1 0 1 1 1 0 0 0

Werbung
Digitales Suchen / Digitale Suchbäume
Verschiedene Suchverfahren laufen in der Weise ab, dass sie
die Suchschlüssel bitweise untersuchen, anstatt in jedem
Schritt vollständige Vergleiche zwischen Schlüsseln
durchzuführen.
Diese Methoden, die digitale Suchverfahren (radix-searching
methods) genannt werden, arbeiten mit den Bits der
Schlüssel selbst, im Gegensatz zu der transformierten
Variante der Schlüssel, die beim Hashing verwendet wird.
Ebenso wie im Falle der digitalen Sortierverfahren gilt, dass
diese Methoden von Nutzen sein können, wenn die Bits der
Suchschlüssel leicht zugänglich und die Werte der
Suchschlüssel gut verteilt sind.
G.Heyer
1
Algorithmen und Datenstrukturen
Die Hauptvorteile sind, dass
• sie ohne Komplikationen, die bei ausgeglichenen Bäumen
auftreten, ein annehmbares Verhalten im ungünstigsten Fall
gewährleisten,
• sie einen einfachen Weg zur Behandlung von Schlüsseln mit
variabler Länge bieten,
• einige von ihnen Einsparungen von Speicherplatz
ermöglichen, indem sie einen Teil des Schlüssels innerhalb
der Suchstruktur speichern und dass
• sie einen sehr schnellen Zugriff auf die Daten realisieren
können, der sowohl mit binären Suchbäumen als auch mit
Hashing vergleichbar ist.
G.Heyer
2
Algorithmen und Datenstrukturen
Die Nachteile sind, dass
• Daten mit einer gewissen Systematik zu entarteten Bäumen
mit schlechtem Verhalten führen können und
• dass einige der Verfahren den Platz sehr ineffizient
ausnutzen.
Wie die digitalen Sortierverfahren sind auch diese Methoden
dazu bestimmt, spezielle Eigenschaften der Architektur
eines Computers auszunutzen.
G.Heyer
3
Algorithmen und Datenstrukturen
Digitale Suchbäume
Das einfachste digitale Suchverfahren ist die Suche mit
digitalen Bäumen; der Algorithmus ist genau der gleiche wie
der für die Suche in einem Binärbaum, mit dem Unterschied,
dass in dem Baum nicht entsprechend dem Ergebnis des
Vergleiches zwischen den Schlüsseln verzweigt wird, sondern
entsprechend den Bits des Schlüssels.
Auf der ersten Ebene wird das führende Bit benutzt, auf der
zweiten Ebene das zweite führende Bit usw., bis ein äußerer
Knoten vorgefunden wird.
Das Programm hierfür ist praktisch das gleiche wie für die
Suche in einem Binärbaum. Der einzige Unterschied ist, dass
die Vergleiche der Schlüssel durch Aufrufe der Funktion bits
ersetzt werden, die beim digitalen Sortieren verwendet
wurde.
G.Heyer
4
Algorithmen und Datenstrukturen
unsigned bits ( unsigned x, int k, int j )
{ return (x >> k ) & ~ (~ 0 << j) ; }
j sind Bits, die k Stellen von rechts in x erscheinen.
Die Funktion kann in Maschinensprache effizient implementiert
werden, indem um k Bits nach rechts geschoben wird und dann
alle Bits außer den rechts befindlichen j Bits auf 0 gesetzt werden.
int digitalsearch ( int v)
{
struct node *x = head;
int b = maxb;
z -> key = v ;
while ( v != x -> key)
x = ( bits (v, b--,1)) ? x -> r : x -> l ;
return x -> info;
}
G.Heyer
5
Algorithmen und Datenstrukturen
Datenstruktur:
die gleiche wie die für elementare binäre Suchbäume
Die Konstante maxb ist die Anzahl der Bits in den Schlüsseln,
die zu sortieren sind. Für das Programm wird angenommen,
dass das erste Bit in jedem Schlüssel ( das (maxb + 1) -te von
rechts) 0 ist, so dass die Suche bei head beginnt, welches eine
Verkettung ist, die auf den Kopfknoten eines Baumes mit dem
Schlüssel 0 und mit einer auf den Suchbaum zeigenden
linken Verkettung zeigt.
Daher ist die Prozedur zur Initialisierung für dieses
Programm die gleiche wie für die Suche in einem
Binärbaum, abgesehen davon, dass man mit
head -> l = z anstatt mit head -> r = z beginnt.
Hier wird vorausgesetzt, dass alle Schlüssel, die in der
Datenstruktur auftreten, unterschiedlich sind.
G.Heyer
6
Algorithmen und Datenstrukturen
A
00001
S
10011
E
00101
R
10010
C
00011
H
01000
I
01001
N
01110
G
00111
X
11000
M
01101
P
10000
L
01100
G.Heyer
Annahme:
der i-te Buchstabe des Alphabets wird
durch die aus fünf Bits bestehende
Binärdarstellung von i repräsentiert.
Um Konsistenz mit bits zu erreichen,
betrachten wir die Bits von rechts nach
links mit 0 bis 4 durchnumeriert.
( demnach ist Bit 0 das einzige von 0
verschiedene Bit von A, und Bit 4 ist das
einzige von 0 verschiedene Bit von P)
7
Algorithmen und Datenstrukturen
Ein digitaler Suchbaum
A
0
1
E
0
0 C
1
0
0 H 1
1
0 G 10
S
I 1
0
0
0 L
G.Heyer
0
M
N
1 0
1
R
P
1
0 X
1
1
1
1
8
Algorithmen und Datenstrukturen
Prozedur für das Einfügen in digitale Suchbäume
digitalinsert (int v, int info )
{
struct node *p, *x = head;
int b = maxb;
while (x != z )
{
p=x;
x = ( bits ( v, b--, 1 )) ? x--> r : x --> l ;
}
x = (struct node *) malloc (sizeof *x);
x --> key = v ; x --> info = info ; x --> l = z ; x --> r = z ;
if ( bits ( v, b+1, 1 ) ) p --> r = x ; else p --> l = x;
}
G.Heyer
9
Algorithmen und Datenstrukturen
Beispiel: Einfügen eines neuen Knotens,
wenn der Schlüssel Z = 11010 zu dem Baum hinzugefügt wird.
Durchlaufen des digitalen Suchbaums:
• zweimal nach rechts wenden, da die beiden führenden Bits
von Z 1 sind,
• dann nach links, wo der äußere Knoten links von X liegt, wo Z
eingefügt wird.
Der ungünstigste Fall für Bäume, die mit digitaler Suche erzeugt
werden, ist viel besser als für binäre Suchbäume, wenn die Anzahl
der Schlüssel groß ist und die Schlüssel nicht lang sind. Die Länge
des längsten Pfades in einem digitalen Suchbaum ist gleich der
längsten Übereinstimmung in den führenden Bits zwischen zwei
beliebigen Schlüsseln im Baum, und diese ist für viele
Anwendungen meist relativ klein (z. B. wenn die Schlüssel aus
zufälligen Bits bestehen ).
G.Heyer
10
Algorithmen und Datenstrukturen
Eigenschaften eines digitalen Suchbaumes:
Ein Suchen oder Einfügen in einem digitalen Suchbaum
erfordert durchschnittlich ungefähr lg N Vergleiche und im
ungünstigsten Fall b Vergleiche, wenn der Baum aus N
zufälligen Schlüsseln mit b Bits erzeugt wurde.
Es ist offensichtlich, dass kein Pfad jemals länger sein kann
als die Anzahl der Bits in den Schlüsseln; z. B. kann ein
digitaler Suchbaum, der aus Schlüsseln mit acht Zeichen
erzeugt wurde, mit beispielsweise sechs Bits pro Zeichen,
keinen Pfad besitzen, der länger als 48 ist, selbst wenn es
Hunderttausende von Schlüsseln gibt. Aus einer Analyse geht
hervor, dass digitale Suchbäume nahezu ausgeglichen sind,
da das „nächste“ Bit eines zufälligen Schlüssels mit der
gleichen Wahrscheinlichkeit 0 oder 1 sein kann, so dass auf
beide Seiten eines jeden Knotens jeweils die Hälfte entfällt.
G.Heyer
11
Algorithmen und Datenstrukturen
Digitale Such-Tries
Sehr oft liegt der Fall vor, dass Suchschlüssel sehr lang sind,
vielleicht zwanzig Zeichen oder mehr. In einer solchen
Situation können die Kosten, die beim Vergleich eines
Suchschlüssels hinsichtlich der Gleichheit mit einem
Schlüssel aus der Datenstruktur entstehen, zu
dominierenden Kosten werden, die nicht vernachlässigt
werden können.
Bei der Suche mit Hilfe digitaler Bäume wird ein solcher
Vergleich bei jedem Knoten des Baumes vorgenommen.
Ziel: Verringerung der Vergleiche
G.Heyer
12
Algorithmen und Datenstrukturen
Neue Idee:
die Schlüssel nicht im Knoten des Baumes zu speichern,
sondern stattdessen alle Schlüssel in äußeren Knoten des
Baumes anzuordnen. Das heißt, anstatt für äußere Knoten
der Struktur z zu verwenden, sieht man Knoten vor, die die
Suchschlüssel enthalten.
Es entstehen 2 Typen von Knoten:
• innere Knoten, die nur Verkettungen zu anderen Knoten
enthalten und
• äußere Knoten, die Schlüssel und keine Verkettungen
enthalten.
(Fredkin nannte diese Methode „trie“, da sie für das
Wiederauffinden „retrieval“ von Nutzen ist.)
G.Heyer
13
Algorithmen und Datenstrukturen
Suchen eines Schlüssels in einer solchen Struktur:
Entsprechend seiner Bits abzweigen (aber kein Vergleich ) bis man
an einen äußeren Knoten gelangt.
Jeder Schlüssel im Baum wird in einem äußeren Knoten des Pfads
gespeichert, der von dem führenden Bitmuster des Schlüssels
beschrieben wird, und jeder Suchschlüssel gelangt zu einem
äußeren Knoten, so dass ein vollständiger Vergleich der Schlüssel
die Suche beendet.
Beispiel eines (binären) digitalen Such-Tries für die
Schlüssel A S E R C
E
A
C
R
G.Heyer
14
S
Algorithmen und Datenstrukturen
Interessante Eigenschaften eines digitalen Such-Trie
Die Struktur des Trie ist unabhängig von der Reihenfolge, in
der die Schlüssel eingefügt werden. Für jede gegebene Menge
von unterschiedlichen Schlüsseln existiert ein eindeutiger Trie.
Für die Implementation dieses Verfahrens in C sind zwei Typen
von Knoten erforderlich, wobei Verkettungen in inneren
Knoten auf Knoten beider Typen zeigen können.
Der linke Unterbaum eines binären digitalen Such-Trie enthält
alle Schlüssel, die als führendes Bit 0 haben; der rechte
Unterbaum enthält alle Schlüssel, die 1 als führendes Bit
haben. Dies führt zu einer unmittelbaren Entsprechung zum
digitalen Sortieren. Bei der Suche mit binären Tries wird die
Datei in genau der gleichen Weise zerlegt wie bei Radix
Exchange Sort. Diese Entsprechung ist analog zu der
Entsprechung zwischen der Suche in einem Binärbaum und
Quicksort.
G.Heyer
15
Algorithmen und Datenstrukturen
Weitere Eigenschaften von digitalen Such-Tries
Ein Suchen oder Einfügen in einem digitalen Such-Trie
erfordert ungefähr lg N Bitvergleiche für eine
durchschnittliche Suche und b Bitvergleiche im ungünstigsten
Fall, wenn der Baum aus N zufälligen Schlüsseln mit b Bits
erzeugt wurde.
Eine störende Eigenschaft von digitalen Tries, welche sie von
den anderen Typen von Suchbäumen unterscheidet , ist die
„Einweg-“Verzweigung, die für Schlüssel erforderlich ist, die
eine große Anzahl Bits gemeinsam haben. Zum Beispiel
erfordern Schlüssel, die sich nur im letzten Bit unterscheiden,
einen Pfad, dessen Länge gleich der Länge des Schlüssels ist,
gleichgültig, wie viele Schlüssel im Baum vorhanden sind. Die
Zahl der inneren Knoten kann um einiges größer sein als die
Zahl der Schlüssel.
G.Heyer
16
Algorithmen und Datenstrukturen
Ein digitaler Such-Trie, der aus N zufälligen Schlüsseln
mit b Bits erzeugt wurde, besitzt im Durchschnitt ungefähr
N/ln2 = 1,44 N Knoten.
Beispiel: Ein Such-Trie, der aus 95 zufälligen Schlüsseln mit 10
Bits erzeugt wurde, besitzt 131 Knoten.
Ziel: Die Höhe von Tries ist zwar durch die Anzahl von Bits in
den Schlüsseln begrenzt, doch wäre es wünschenswert, die
Möglichkeit zur Verarbeitung von Datensätzen mit sehr langen
Schlüsseln (z. B. 1000 Bits oder mehr ) zu betrachten.
Die Schlüssel könnten evtl. eine gewisse Einheitlichkeit
aufweisen, wie dies bei Daten der Fall sein könnte, die kodierten
Text darstellen. Ein Weg, um die Pfade in den Bäumen zu
verkürzen, besteht in der Verwendung von deutlich mehr als zwei
Verkettungen pro Knoten ( obwohl dadurch ein „Platz“-Problem
infolge der Verwendung zu vieler Knoten entstehen kann; ein
anderer Weg ist das „Verkürzen“ von Pfaden, die EinwegAbzweigungen zu einzelnen Verkettungen enthalten.
G.Heyer
17
Algorithmen und Datenstrukturen
Huffman-Codierung
Der erste Schritt zur Erzeugung des Huffmann-Codes besteht
darin, durch Zählen der Häufigkeit jedes Zeichens innerhalb
der zu kodierenden Zeichenfolge zu ermitteln.
Das folgende Programm ermittelt die Buchstabenhäufigkeiten
einer Zeichenfolge a und trägt sie in ein Feld count [26] ein.
Die Funktion index dient dazu, dass der Häufigkeitswert für
den i-ten Buchstaben des Alphabets in dem Eintrag count [i]
eingetragen wird, wobei wie üblich der Index 0 für das
Leerzeichen verwendet wird.
for (i = 0; i <= 26 ; i++ ) count [i] = 0;
for ( i = 0; i < M ; i++ ) count [ index(a[i])] ++;
Nehmen wir z. B. an, dass wir die Zeichenfolge
“A SIMPLE STRING TO BE ENCODEC USING A
MINIMAL NUMBER OF BITS” kodieren möchten.
Häufigkeiten sind: 11 Leerzeichen, 3 A, 3 B usw.
G.Heyer
18
Algorithmen und Datenstrukturen
Häufigkeitstabelle zum Beispielsatz:
ABCDEFGHIJKLMN OPQRSTUVWXYZ
k 0 1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
count[k]
11 3 3 1 2 5 1 2 0 6 0 0 2 4 5 3 1 0 2 4 3 2 0 0 0 0 0
Der nächste Schritt ist der Aufbau des Kodierungs-Tries
entsprechend den Häufigkeiten.
Während der Erzeugung des Trie betrachten wir ihn als eine
binären Baum mit Häufigkeiten, die in den Knoten
gespeichert sind; nach seiner Erzeugung betrachten wir ihn
dann als einen Trie für die Kodierung, in der beschriebenen
Weise.
G.Heyer
19
Algorithmen und Datenstrukturen
Zunächst wird für jede von null verschiedene Häufigkeit ein
Knoten des Baumes erzeugt.
Dann werden die beiden Knoten mit den kleinsten
Häufigkeiten ausgewählt, und es wird ein neuer Knoten
erzeugt, der diese beiden Knoten als Nachfolger hat und
dessen Häufigkeit einen Wert hat, der gleich der Summe der
Werte für seine Nachfolger ist. ( Falls mehr als 2 Knoten mit
der kleinsten Häufigkeit vorhanden sind, ist es gleichgültig,
welche benutzt werden.)
Danach werden die beiden Knoten mit der kleinsten
Häufigkeit in diesem Wald ermittelt und eine neuer Knoten
wird auf die gleiche Weise erzeugt. In dem man in dieser
Weise fortfährt, werden immer größere Unterbäume
hergestellt und gleichzeitig bei jedem Schritt die Anzahl der
Bäume im Wald um eins verringert (zwei werden entfernt,
einer wird hinzugefügt). Am Schluß sind alle Knoten
miteinander zu einem einzigen Baum verbunden.
G.Heyer
20
Algorithmen und Datenstrukturen
Beispiel: Erzeugung eines Huffman-Baumes
6 3 3 2 4 5 3 1 1
2 4
2
6 3 3 2 4 5 3
1
2 4 3 2 2 5 1 2 11
1
2
6 3 3 2 4 5 3
1
3 2 2 5 1 2 11
2 4
1
3
3 2 2 5
1
11
2
...
G.Heyer
21
Algorithmen und Datenstrukturen
Nächste Schritte zur Erzeugung des Tries
6 3
3
4
5 3
5
2
1
4
3
4
2
4
2
2
5
2
3
1
11
2
1
Zum Schluss liegen Knoten mit geringer Häufigkeit weit
unten im Baum, Knoten mit großen Häufigkeiten in der
Nähe der Wurzel des Baumes.
G.Heyer
22
Algorithmen und Datenstrukturen
Vollständiger Baum
60
23
11
5
37
16
12
6
6
3
6
3
3
8
3
1
21
2
4
2
8
4
2
4
4
5
23
5
2
2 2
1
G.Heyer
11
10
3
1
Algorithmen und Datenstrukturen
Nunmehr kann der Huffman-Code abgeleitet werden,
indem die Häufigkeiten an den unteren Knoten einfach
durch die zugehörigen Buchstaben ersetzt werden und der
Baum dann als ein Trie für die Kodierung angesehen wird,
wobei, genau wie oben „links“ einem Bit 0 und „rechts“
einem Bit 1 im Code entspricht.
Der Code für N ist 000, der Code für I ist 001,
der Code für C ist 110100 usw.
Die kleine Zahl oberhalb jedes Knotens in diesem Baum ist
der Index für das Feld count, der angibt, wo die Häufigkeit
gespeichert ist. Diese Angabe wird für die Untersuchung im
Programm benötigt .
Folglich ist count[33] = 11, der Summe der Häufigkeitszähler
für N und I.
G.Heyer
24
Algorithmen und Datenstrukturen
Skizze für die Huffman-Kodierung zum Beispielsatz
27
28
29
33
N
31
32
I
O
37
B
36
38
A
35
G
34
40
41
42
F
30
S M
U
L
39
E
43 T
D R
C
G.Heyer
25
P
Algorithmen und Datenstrukturen
Huffman-Kodierung ist die beste Kodierung,
da Buchstaben mit großen Häufigkeiten sich näher an der
Wurzel befinden und mit weniger Bits verschlüsselt werden
als bei anderen Kodierungen.
Eigenschaft: Die Länge der kodierten Zeichenfolge ist gleich
der gewichteten äußeren Pfadlänge des Huffman-Baumes.
Die „gewichtete äußere Pfadlänge“ eines Baumes ist gleich
der über alle äußeren Knoten gebildeten Summe der
Produkte des „Gewichts“ (zugehöriger Häufigkeitszähler)
mit der Entfernung von der Wurzel. Dies ist eine Möglichkeit, die Länge der kodierten Zeichenfolge zu berechnen; sie
ist äquivalent zu der über alle Buchstaben gebildeten Summe
der Produkte der Häufigkeit des Auftretens eines
Buchstabens mit der Anzahl der Bits bei jedem Auftreten.
G.Heyer
26
Algorithmen und Datenstrukturen
Eigenschaft:
Kein Baum mit den gleichen Häufigkeiten bei den äußeren
Knoten hat eine kleinere gewichtete äußere Pfadlänge als der
Huffman-Baum.
Mit Hilfe des gleichen Prozesses kann ein beliebiger Baum
rekonstruiert werden, um den Huffman-Baum zu erzeugen,
doch ohne bei jedem Schritt unbedingt die zwei Knoten mit
dem kleinsten Gewicht auszuwählen. Mittels Induktion lässt
sich beweisen, dass keine Strategie zu einem besseren
Ergebnis führen kann, als die, bei der zuerst die beiden
kleinsten Gewichte ausgewählt werden.
G.Heyer
27
Algorithmen und Datenstrukturen
Herunterladen