PDF

Werbung
http://www.mpi-sb.mpg.de/~sschmitt/info5-ss01
IS
UN
R
Lösungsvorschläge für das 8. Übungsblatt
Letzte Änderung am 27. Juni 2001
Aufgabe 1
mit linear probing: h(x,i) = ((x mod 11) + i) mod 11
h(16,0)=5
h(44,0)=0
44
16
16
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7 8 9 10
h(21,0)=10
h(5,0)=5; h(5,1)=6
44
44
16
16 5
21
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6
h(19,0)=8
h(22,0)=0; h(22,1)=1;
44
19
44 22
16 5
16 5
21
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6
h(33,0)=0..h(33,2)=2;
h(8,0)=8; h(8,1)=9
44 22
19 8 21
44 22 33
16 5
16 5
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6
h(30,0)=8..h(30,6)=3
h(27,0)=5..h(27,2)=7
44 22 33
44 22 33 30
16 5 27 19 8 21
16 5
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6
7 8 9 10
21
7 8 9 10
19
21
7 8 9 10
19 8 21
7 8 9 10
27 19 8 21
7 8 9 10
mit double hashing: h(x,i) = ((x mod 11) + i*(1+ x mod 10)) mod 11
h(16,0)=5
h(44,0)=0
44
16
16
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8 9 10
h(21,0)=10
h(5,0)=5; h(5,1)=0;h(5,2)=6
44
44
16
21
16 5
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7
h(19,0)=8
h(22,0)=0; h(22,1)=3;
22
44
19
44
16 5
16 5
21
0 1 2 3 4 5 6 7 8 9 10
0 1 2 3 4 5 6 7
h(8,0)=8; h(8,1)=6;h(8,2)=4
22 8 16 5
44
0 1 2 3 4 5 6 7
h(27,0)=5;h(27,1)=2
44 33 27 22 8 16 5
0 1 2 3 4 5 6 7
19
21
8 9 10
19
21
8 9 10
h(33,0)=0..h(33,3)=1
22 8 16
44 33
0 1 2 3 4 5
h(30,0)=8; h(30,1)=9
44 33 27 22 8 16
0 1 2 3 4 5
8 9 10
21
8 9 10
19
21
8 9 10
19
5
21
6 7 8 9 10
19 30 21
5
6 7 8 9 10
S
SS 2001
E R SIT
S
Schmitt, Schömer
SA
IV
A
Grundlagen zu
Datenstrukturen und Algorithmen
A VIE N
Aufgabe 2
1. Da 15 keine Primzahl ist, ist der Restklassenring Z/15Z nicht nullteilerfrei. Ziel des “probing” ist, dass nacheinander Plätze der Hashtabelle ausprobiert werden. Ist c ein Teiler von
m, so werden nicht alle Plätze adressiert. Deshalb sind alle Zahlen c ungeeignet, die nicht
teilerfremd zu 15 sind. Dies sind 3, 5, 6, 9, 10, 12. Sei z.B. c = 3. Dann ist h(x, 0) = h(x, 5).
2. Wie in Aufgabe eins schon bemerkt, müssen m und c teilerfremd sein, d.h. ggT (c, m) = 1.
Es gilt:
∃0 < d < m : d | c ∧ d | m ⇒ ∃1 ≤ k, l ≤ m : c = d · k ∧ m = d · l
⇒ h(x, l) = (h(x) + c · l) mod m = (h(x) + d · k · l) mod m
= (h(x) + d · m) mod m = h(x) mod m = h(x, 0)
Damit alle Plätze der Hashtabelle adressiert werden, muss l = m gelten. Daraus folgt d = 1.
Also sind diejenigen Paare (c, m) sinnvoll mit ggT (c, m) = 1.
Aufgabe 3
a) Die Zahl 257 ist eine Primzahl, daher können wir die 1-universelle Klasse der Hashfunktionen
aus der Vorlesung verwenden. Ein String der Länge l ist dabei ein l-Tupel von Zahlen
s = (sl−1 , . . . , s0 ) und kann als eine Zahl in der Darstellung zur Basis m = 257 betrachtet
werden. Die Hashfunktionen sind dann gegeben durch
ha (s) = a × s
für beliebige Strings a der Länge l, wie in der Vorlesung.
b) Wir wählen jetzt Strings a beliebiger Länge und betrachten auch die Funktionen ha (s) =
a × s wie eben. Seien x, y Strings der Länge lx , ly und l = max{lx , ly }. Dann sind von a nur
die ersten l Stellen wichtig, die hinteren Stellen sind unwichtig. Genau wie in dem Beispiel
der Vorlesung kann man dann zeigen, daß diese Klasse von Funktionen 1-universell ist.
Wie wählt man zufällig einen String a unendlicher Länge? Man wählt sich zufällig Zahlen
aus {0, 1, . . . , 256} für jede Stelle, aber nur soviel, wie man gerade braucht. Hat man z.B.
einen String der Länge 19 zu hashen, wählt man sich die ersten 19 Stellen von a. Hasht man
danach einen String der Länge 99, so läßt man die ersten 19 Stellen von a wie vorher und
wählt sich zufällig die letzten 80 Stellen.
Aufgabe 4
(a) Ein Binärbaum ist so aufgebaut, daß das linke Kind eines jeden Knotens kleiner ist als der
Knoten selbst. Somit ist das Minimum des Teilbaums mit Wurzel v gleichzeitig auch das
Minimum des Teilbaums mit Wurzel v →left, sofern er nicht NULL ist. Besitzt v kein linkes
Kind, so existiert kein kleineres Element im Teilbaum, und v ist selbst das Minimum. Diese
induktive Definition führt uns zur folgenden Implementierung:
// ermittelt das Minimum des Teilbaums mit Wurzel v
handle minimum( handle v)
{
if( NULL == v->left) return v;
return( minimum( v->left));
}
Es stellt sich also heraus, daß das Minimum gerade das linkeste Kind ist, und analog dazu
ist das Maximun das rechteste, was zu dieser Implementierung führt:
// ermittelt das Maximum des Teilbaums mit Wurzel v
handle maximum( handle v)
{
if( NULL == v->right) return v;
return( maximum( v->right));
}
Beide Implementierungen haben logarithmische Laufzeit.
(b) Zeige: Es gibt nur diese 2 Fälle:
(i) v besitzt ein rechtes Kind. Zeige: succ(v) = minimum(v->right)
∗ Alle Elemente im linken Teilbaum von v (falls ein solcher existiert) sind kleiner als
v, kommen also nicht in Frage.
∗ Ist v ein rechtes Kind von v->parent, dann sind alle Elemente im linken Teilbaum
von v->parent sowie v->parent selbst kleiner als v.
∗ Geht man solange nach oben, wie man das rechte Kind eines Elternknotens ist, so
sind diese Elternknoten und ihre linken Teilbäume (genau wie oben) alle kleiner
als v.
∗ Irgendwann auf dem Weg nach oben sind wir das linke Kind eines Knotens w.
Dieser Knoten ist dann größer als v, aber auch größer als minimum(v->right), da
der rechte Unterbaum von v auch links unterhalb w steht.
∗ Ebenso ist alles, was rechts von w steht, größer als minimum(v->right).
∗ Man kann jetzt weiter bis zur Wurzel gehen und wie eben argumentieren: Ist man
das rechte Kind, dann trifft man nur auf Elemente, die kleiner als v sind, ist man
das linke Kind, so trifft man nur auf Elemente, die größer als minimum(v->right)
sind.
(ii) v besitzt kein rechtes Kind. Man geht solange nach oben, wie man das rechte Kind
eines Knotens ist. Ist man das linke Kind eines Knotens w, so ist dieser gleich succ(v).
∗ Auf dem Weg nach oben, bevor man bei w ankommt, sind alle Knoten die man
trifft und ihre linken Teilbäume kleiner als v.
∗ Der Knoten w ist größer als v.
∗ Alle Knoten im rechten Teilbaum von w (falls der existiert) sind größer als w.
∗ Jetzt gehen wir wie in Teil (i) von w aus nach oben. Ist der betrachtete Knoten ein
rechtes Kind des Elternknotens p, dann ist p und der linke Teilbaum von p kleiner
als v (da v im rechten Teilbaum von p liegt).
∗ Ist der betrachtete Knoten ein linkes Kind von p, dann ist p und der rechte Teilbaum von p größer als w.
∗ Genau wie eben kann man mit dieser Argumentation bis zur Wurzel gehen.
(c) Dies sollte uns nun keine Schwierigkeiten mehr bereiten:
// findet das nächst kleinere Element
handle pred( handle v)
{
if( v->left!=0) return maximum( v->left);
handle p = v->parent;
while( p!=0 && v==p->left)
{
v = p;
p = v->parent;
}
return(p);
}
Die Methode hat die gleiche Laufzeit wie succ.
Herunterladen