Simon Putzke
1
Inhaltsverzeichnis
1 Analyse von Algorithmen 4
1.1 Effizienz (insbesondere Laufzeit) von Algorithmen . . . . . . . . . . . . . . . . . . . . . 4
1.1.1 Experimentelle Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.2 Theoretische Analyse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.3 Pseudo- Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.4 Registermaschine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.5 Laufzeit von Algorithmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.6 Asymptotisches Laufzeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.1.7 Rekursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.1.8 Rekursion auf der RAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.2 Datenstrukturen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2.1 Beispiel Stapel (Stack) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.2.2 “Indirekte” Anwendung von Stapeln . . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3 Dynamisierung Array- basierter Datenstrukturen . . . . . . . . . . . . . . . . . . . . . . 20
2 Datenabstraktion 24
2.1 Geheimnisprinzip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.2 Abstrakte Datentypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.2.1 Explizite Schnittstellenbeschreibung in Java . . . . . . . . . . . . . . . . . . . . . 26
2
3.6.4 Tiefensuche in Bäumen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.7 ADT Wörterbuch (Dictionary) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3.7.1 Implementierung des ADT Wörterbuch . . . . . . . . . . . . . . . . . . . . . . . 46
3.7.2 Implementierung durch Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.7.3 Hashcodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
3.7.4 Zufallsexperiment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
3.7.5 Universelle Hashfunktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3
16. Oktober 2008
Frage nach
(Funktion die einer Eingabe die Laufzeit des Algorithmus darauf zuordnet)
• Implementierung
• Messung der Laufzeit auf vielen, “typischen” Eingaben
Problematisch!
4
1.1.2 Theoretische Analyse
Bsp.
ArrayMax (A, n)
Input: Feld A [1, ..., n] von n ganzen Zahlen
max
Output: 1≤i≤n A [i]
currentMax ← A [1]
for i = 2 to n
if current Max < A [i] then currentMax = A [i]
return currentMax
Im Detail:
“Verboten”:
ArrayMax+ (A, n)
max
return 1≤i≤n A [i]
5
1.1.4 Registermaschine
Pseudo Code ist O.K. falls jede primtive Operation durch ≤ 10 RAM- Anweisungen ausgeführt werden
kann.
Def:
A Algorithmus (RAM- Programm)
I Eingabe für A
TA (I) = Anzahl der RAM Operationen die A auf Eingabe I macht “Rechenzeit von A uf I”
TA (n) = max I,Groesse
max
von I=n TA (I) “worst- case Rechenzeit von A”
Algorithm d o u b l e ( x )
6
Input x ∈ N
Output 2x
y <− x
y <− y + x
return y
(Pseudocode)
Algorithm d o u b l e ( x )
Input x ∈ N
Output 2x
z <− x
y <− x
f o r i =1 t o z do
y <− y + 1
return y
(Pseudocode)
TA (x) − ”3 + 2x
Typischerweise analyisieren wir Algorithmen im Pseudocode (Laufzeit ≈Anzahl der Pseudocodezeilen)
Das ist zulässig, solange der verwendete Pseudo- Code die Eigenschaft hat, dass jede Code- Zeile durch
konstant viele RAM- Operationen realisiert wrrden können.
7
1.1.6 Asymptotisches Laufzeit
• “moderate” Änderungen des Maschinenmodells ändern die Laufzeit nur um einen konstanten
Faktor.
• die asymptotische Laufzeit ignoriert konstante Faktoren und Terme niederer Ordnung.
Bsp.:
TA (n) = 1, 75n3 + (0, 4 log2 n) = Θ(n3 )
1. f (n) = O(g(n))
2. f ∈ O(g)
BSP :
O-Notation HOWTO
1.)
!d
f (n) = i=0 ai ni mit ai ≥ 0
f (n) = O(nd )
2.)
Wir sagen ”2n = O(n)” statt ”2n = O(n2 )”
3.)
Wir sagen ”2n = O(n)” statt ”2n = O(3n − 6)”
4.)
Die Analogie O=
ˆ ≤, Ω=
ˆ ≥, θ=
ˆ =
klappt oft (aber Vorsicht: nicht immer)
5.)
8
nα = O(nβ ) ∀ α ≤ β
6.)
(log n)α = O(nβ ) ∀α, β > 0
Beispiel:
Algorithm PrefixAverage (X, n)
Input X[0], . . . , X[n − 1], n
!
Output A[0], . . . , A[n − 1] mit A[i] = 1
i+1 j≤i A[j]
A<−l e e r e s Feld mit n Elementen //1−mal d u r c h l a u f e n
f o r i = 0 t o n−1 do //n−mal d u r c h l a u f e n
sum <− 0 //n−mal d u r c h l a u f e n
f o r j = 0 t o i do / / ( i +1 mal d u r c h l a u f e n )
sum <− sum + X[ j ] //im i −t e n D u r c h l a u f d e r ä u ß e r e n S c h l e i f e
A[ i ] <− ( sum ) / ( i +1) //n−mal d u r c h l a u f e n
return A //1−mal d u r c h l a u f e n
Gesamtkosten:
n−1
&
O(1) + O(n) + O( (i + 1))
" #$ % " #$ %
i=0
1&7 2&6,3 " #$ %
4&5
Laufzeit O(n)
1.1.7 Rekursion
Beispiel:
Potenzieren x, n ∈ N
p(x, n) := xn = x
" · .#$
. . · x%
n−mal
9
Lösung 1: Iterartiv O(n)
'
x · p(x, n − 1) n>0
Lösung 2: p(x, n) =
1 n=0
Algorithm Pow (x,n)
Input x, n ∈ N
Output xn
i f n = 0 then r e t u r n 1
r e t u r n x ∗ Pow ( x , n−1)
Laufzeit:
'
O(1) n=0
T (n) =
T (n − 1) + O(1) n>0
Lösung (n > 0) mit C > 0
T (n) ≤ T (n − 1) + C ≤ T (n − 2) + 2 · C ≤ T (n − 3) + 3 · C
per Induktion: T(n) ≤ T(n − k) + k · C
∀k ≤ 1 für k = n: T (n) ≤ T (0) + n · C
Beweis:
x · P ow(x, n − 1)
x∗Pow( x , n−1)=x∗x∗Pow( x , n−2)
=x∗x∗x∗Pow( x , n−3)
=x ∗ ( n−mal ) ∗ x∗Pow( x , 0 ) //Pow( x ,0)=1
Algorithm PowFast(x,n)
i f n=0 r e t u r n 1
i f n=2k then
z <− PowFast ( x , 1 / 2 ) // n i c h t s o ! S y n t a k t i s c h a b e r k o r r e k t
return z∗z
i f n=2k+1 then
z <− PowFast ( x , ( n −1)/2)
r e t u r n z ∗ z ∗x
10
Laufzeitanalyse
Beschränken auf n = 2r für r ≥ 0
'
O(1) n=1
T (n) = , -
T n2 + O(1) n>1
S(r) := T(2r )
'
O(1) r=1
S(r) =
S(r − 1) + O(1) r>0
wie in (2:)
S(r) = O(r) = T (2r )
also
T (n) = O(log n)
28.Oktober 2008
1.1.7.1 Rekursionsbäume
Bsp.: PowFast
Fibonacci Zahlen
Bsp: Fibonacci- Zahlen
11
F(0)=F(1)=1
F(n)=F(n-1)+F(n-2), n ≥ 2
Definition:
Die Rechenzeit von A auf x lässt sich bestimmen, indem man die in den Knoten des Berechnugsbam
von A auf x anfallende Arbeit aufsummiert.
Bsp: Mergesort
12
Analyse
13
Gesamtkosten:
n n n n n n
c · n + c( ) + c( ) + c( ) + c( ) + c( ) + c( ) + . . .
"#$%
" 2 #$ 2 % " 4 4 #$ 4 4%
W urzel
Kinder d. W urzel Enkel der W urzel
= c · (n + 2)
n
+ 2)
n
+ ( n4 + n
4 + n
4 + n4 ) + . . .)
= c(n + n + n + n + . . .)
= c · n (1 + 1 + 1 + . . . + 1) = c · n· Höhe des Baumes = c · n · log n
" #$ %
#Rekursionsstuf en
14
= F (n − 2) + F (n − 3) + F (n − 2)
≥ 2F (n − 2)
≥ 2(2F (n − 4))
≥ 2(2(2 · F (n − 6)))
≥ 2i · F (n − 2i) (per Induktion)
Damit (i = u2 )
n √
F (n) = 2 2 = ( 2)n
Alternativen
Iteration:
Ind.
f$n = M · f$n−1 = M · M · f$n−2 = M · M · M · f$n−3 = M · . . . · M · f$n−i (i ≥ 1)
" #$ %
i−mal
= M i · f$n−i
i=n−1
= M n−1 · f$1
Kann in O(log n) Zeit durch schnelle (Matrix-) Exponentiation berechnet werden.
Algorithm min ( )
x <− 5
subroutine1 (x)
15
Algorithm s u b r o u t i n e 1 ( i )
k <− i +1
subroutine2 (k)
Algorithm s u b r o u t i n e ( k )
y <− 6
1.2 Datenstrukturen
Schema zur Organisation von Daten, so dass gewisse Operationen auf / Manipulationen von Daten
effektiv durchführbar sind.
Manipulation von von Objekten erfolgt nach dem LIFO (last in- first out) Prinzip (hier: “Objekte”=int)
d.h. wir benötigen die Operationen
Implementierung:
16
• int-Array F mit M Einträgen
• Zeiger top auf oberstes Element (int top=-1)
Java- Implementierung:
c l a s s i n t ArrayStack {
int F [ ] ;
i n t top ;
i n t M;
i n t ArrayStack ( i n t m) {
M = m;
top = −1;
F = new i n t M[ ] ;
}
hier:
17
• Platzbedarf Θ(M )
• Θ(1) Zeit für push & pop
Probleme:
• Einfügen und Löschen am Anfang der einfach verketteten Liste ist einfach (Θ(1) Zeit )
Beispiel: Gegeben
18
x2 wird von x3 verdeckt, x4 wird von x5 verdeckt. Wäre ein x6 größer als x5 und kleiner als x3, wäre
auch x5 verdeckt.
Span berechnen:
Feld X[0],...,X[1] von n Zahlen
Berechne für alle 0 ≤ i ≤ n − 1
S[i] = max. Anzahl von aufeinanderfolgenden Elementen unmittelbar vor X[i] die kleiner als X[i] sind.
Algorithm Span (X, n )
S <− Neues Feld mit n E i n t r ä g e n
| f o r i = 0 t o n−1 do
| S [ i ] <− 0
| | f o r j = 0 t o i do
| | i f X[ i −j ] " k l e i n e r g l e i c h " X[ i ] do
| | S [ i ]++
| | e l s e break ;
i
n−1
&&
Θ( 1) = Θ(n2 )
i=0 j=0
19
• am Index i
entferne alle Elemente von der Spitze des Stapels die ≤ X[i] sind und zähle span(X[i]) je um
eins hoch
lege X[i] auf Stapel
f o r i =0 t o n−1 do
w h i l e ( ! isEmpty (A)&&((X[ top (A)]) <= X[ i ] ) ) do // e n t f e r n e a l l e Elemente
pop (A) // aus A d i e k l e i n e r a l s X[ i ] s i n d
Analyse:
n push − Operationen
≤n pop − Operationen
≤ 2n isEmpty − Operationen
Stack mit einfach verketteten Listen ⇒ Θ(n) Gesamtlaufzeit.
20
• keine feste Größe
• Wir haben zu jedem Zeitpunkt ein Array in dem alle Elemente des Stapels abgespeichert sind.
• Wenn Platz in diesem Array nicht mehr ausreicht, legen wir ein neues Array doppelter Größer
an und kopieren das alte Feld in den Anfang des neuen Feldes.
Probleme dabei:
Begründung:
1. Eine pop- Op benötigt nur Θ(1) Zeit. D.h. alle pop- Op’s in einer Folge von n push/pop- Op’s
benötigt O(n) Zeit.
21
2. Betrachte Folge von n push- Op’s.
'
O(k) k = 2i
Die k-te push- Operation benötigt Zeit Tk =
O(1) sonst
Gesamtzeit für n push- Operationen
n $log2 n%
& &
Tk = O(n) + T2i
k=0 i=0
$log2 n%
&
= O(n) + O(2i )
i=0
= O(n) + O(n)
n
&
Tk = O(n)
k=0
Definition (amortisiert):
Gegeben sie eine Datenstruktur, für die eine Folge von n Operationen insgesamt T(n) Zeit benötigt.
T (n)
Dann nennen wir n die amortisierten Kosten pro Operation.
22
Buchhaltervorschrift
– kein Kopieren : bezahle Kosten (1$) und lege 1$ auf das DS Sparbuch
– mit Kopieren: bezahle Kosten (# Elemente im Stack) von meinen 2$ auf Sparbuch
2. es gilt cF = 2$ · |F |
• eine push- Op veranlasst, das im Fall mit M Einträgen verdoppelt wird, hat zur Folge, dass
danach mind. M Operationen ausgeführt werden können, die nur 1$ kosten.
• der nächste auffallende Verdopplung kostet 2M $.
Problem: Der Platzbedarf der DS hängt nicht von der Anzahl der Elemente (tatsächlich von der ma-
ximalen Stackgröße) ab, die in der DS gespeichert worden, sondern von der Anzahl der durchgeführten
Operationen.
23
2 Datenabstraktion
2.1 Geheimnisprinzip
Kenntnis der Spezifikationen eines Moduls, Datentyp, Systems ist notwendige und hinreichende Vor-
aussetzung für deren konkrete Benutzung.
Datenabstraktion ist die Anwendung des Geheimnisprinzips auf die Darstellung komplexer Datenstruk-
turen:
• Das Klassenkonzept untersützt die Zusammenfassung von Daten und dem sie manipulierenden
Operationen (in einer syntaktischen Form).
• In Java kann das Verberigen der internen Repräsentation durch Sichtbarkeitsmodifikatoren er-
reicht werden.
– public : überall
– protected : innerhalb des eigenen Pakets und in den Unterklassen
– private : nur innerhalb der umschließenden Klasse
– default : innerhalb des Pakets
• Diese steuern die Sichtbarkeit von Attributen und Methoden
Object pop ( ) . . .
}
24
Problem: direkte Manipulation der Daten möglich.
Stack s = new Stack ( ) ;
st = 124;
s . push ( 3 ) ;
Definition ADT :
Ein ADT ist eine Menge von Objekten mit einer Menge von Operationen auf diesen Objekten.
alternativ:
Ein Typ, dessen Objekte nur über die Operationen seiner Schnittstelle manipuliert werden können.
Beispiel: Stack
Operationen :
push : ( x , S ) −> S
pop : ( S ) −> S
Objekte
Folgen (von Elementen)
↑ nach dem LIFO- Prinzip
25
Reale Welt
“reelle” Objekte mit “rellen” Operatoren
↓ Modellierung
↓ Implementierung
Datenstruktur, Methoden
“Probleme”
9, 1, 2, 5, 7, 5,
push_left push_right
pop_left pop_right
• Standardsichtbarkeit public
Im Programm:
( 1 ) F e s t l e g u n g aud e i n e k o n k r e t e Implementierung
(2) e v t l . andere
S t a c k I n t e r f a c e s = new Stack ( ) ;
26
(3) geht nicht !
S t a c k I n t e r f a c e s = new S t a c k I n t e r f a c e ( ) ;
Pflichten:
Rechte:
Bemerkung:
27
13. November 2008
Motivation:
PQ H;
f o r i = 1 t o n do
H. i n s e r t (A[ i ] ) ;
f o r i = 1 t o n do
p r i n t H. f i n d m i n ( ) ;
H. d e l e t e m i n ( ) ;
28
Laufzeit von PQSort:
TX Laufzeit von X ∈ {findmin, deletemin, insert}
Gesamtlaufzeit: O(n · Tinsert + n · Tfindmin + n · Tdeletemin + n)
, -
Damit: Gesamtlaufzeit O n2
(a)
Implementierung der PWS als einfach verkettete Liste
l·n=m
29
Tfindmin = O(l)
Tinsert = O(l)
Tdeletemin = O(l + m)
Damit:
√
Gesamtlaufzeit : (Optimal für l = m = n)
√
O(n · l + n · m + n) = O(n · n)
(c) Heaps
Ein heapgeordneter Baum für eine Menge S ⊂ U ist ein Baum auf den Elementen von S, wobei gilt:
u Kind von v ⇒ u ≥ v
Bsp.:
30
insbesondere:
interface PrioritätsWarteSchlange {
void i n s e r t ( Object o ) ;
Object findmin ( ) ;
void deletemin ( ) ;
}
31
18. November 2008
* findmin trivial
* deletemin setzt die Wurzel auf ”∞” und lässt sie “absinken” bis zu einem Blatt und entfernt dieses
* insert ausgehend von einer “freien Position” (abhängig von Details der Baumstruktur)
füge neues Objekt ein und lass es “aufsteigen”
• binär
• heap- geordnete Bäume, wo die Tiefe von Blättern sich max im 1 unterscheidet
• alle bis auf einen inneren Knoten genau zwei Kinder haben
Fakt:
Diemaximale Tiefe eines binären Heaos mit n Elementen ist O(log n)
32
• insert auf bin. Heaps:
Schreibe das neue Element in das nächste freie Blatt & lass es aufsteigen, mache es zum rechtesten
Blatt und bestimme das neue rechte nächste freie Blatt
• wir stellen binäre Heaps so dar, dass die letzte Ebene des Baumes von links nach rechts aufgefüllt
ist
• wir “merken” uns das “rechteste” Blatt der letzten Ebene & das erste freie Blatt
33
• Speichere bin. Heap mit n Elementen in Feld der Länge n
• Knoten mit Index i hat linke (rechte) Kind bei Index Index 2i (2i+1)
• “letztes” Element ist bei Index n gespeichert, die erste freie Position bei Index n+1
Laufzeit:
34
20. November 2008
triviale Implementierung
i n t e r f a c e VPWS {
void i n s e r t ( Object o ) ;
void d e l e t e m i n ( ) ;
Object f i n d m i n ( ) ;
void meld (VPWS P ) ;
}
i n t e r f a c e PWS {
void i n s e r t ( Object o ) ;
void d e l e t e m i n ( ) ;
Object f i n d m i n ( ) ;
void d e l e t e m i n ( ) {
P. deletemin ( ) ;
}
35
Vererbung (Einschluss- Polymorphie) in Java
(Polymorphie = Vielgestaltigkeit)
Klasse (bzw. Schnittstelle) Y wird als Erweiterung der Klasse X vereinbart und erbt damit die eigen-
schaften von X.
Syntax:
c l a s s X { Text von X }
Umgesetzt:
i n t e r f a c e VPWS extends PWS {
void meld ( . . . ) ;
}
bzw.
c l a s s VBinaerHeap extends BinaerHeap implements VWPS {
void meld . . .
}
36
3.4 neue Implementierung als Binomialheaps
Binomialbäume:
Bsp:
Es gilt:
Ein Binomialheap mit n Elementen S ist ein Wald von Binomialbäumen in denen die Elemente von S
heap- geordnet gespeichert sind. Jeder Bi kommt dabei höchstens 1x vor. Das gilt immer !
Bsp:
S = {7, 5, 1, 4, 13, 6} n = 6 = 22 + 21 ⇒ B1 und B2
37
Es gilt: wir benötigen Θ(log n)
Binomialbäume in einem Binomialheap für n Elemente
(hint: Binärdarstellung)
Die (Wurzeln) der Binomilabäume sind in einer Liste verkettet, sortiert nach ihrem Grad.
(a) meld
38
25. November 2008
verschmelzen
n=4
8 + 4 + 2 = 23 + 22 + 21
• findmin(P)
• insert(P,x)
• deletemin(P)
– Finde Bi in der Wurzelliste der Minimum speichert (in seiner Wurzel), entferne Bi aus
der Wurzelliste, entferne Wurzel von Bi (resultiert in {B0 , . . . , Bi−1 }) und erzeugen damit
neuen Binärheap.
Verschmelzen den neuen & den alten Heap.
O(log |P |) Zeit
39
Bsp.:
mögliche Lösung
Schnittstellenmethoden zum Einfügen von Objekten liefern einen “Zeiger” auf den Eintrag der Objekte
in der DS.
z.B.:
c l a s s PWSEintrag {
int Prioritaet ;
Object E i n t r a g ;
int Position ;
}
3.6 Bäume
mathematischer Kontext Informatik Kontext
Kreisfreier zusammenhängender Graph gerichteter Graph T = (V, E)
typischerweise gibt es eine (totale Ordnung) Wurzel w ∈ V
auf den Kindern eines Knotens. (u, v) ∈ E
v heißt Kind (Nachfolger) von u
u heißt Erziehungsberechtigter (Vorgänger) von v
ADT Knoten
• speichert Objekte
• Manipulation/Zugriff
void setInfo (Object o);
Object getInfo();
40
3.6.1 Schnittstelle zum ADT Baum (Auswahl)
Knoten getRoot ( ) ;
Knoten g e t P a r e n t ( Knoten k ) ;
boolean a L e a f ( Knoten k ) ;
Knoten g e t C h i l d ( Knoten k , int i ) ;
int g e t D e g r e e ( Knoten k ) ;
41
27. November 2008
Implementierung von Bäumen
Bsp. k=3
h=0 30 = 1
h=1 30 + 3 · 30 = n0 + 3n0 = 4
h=2 4 + 3 · 3 = 13
h=3 13 + 9 · 3 = 40
h
& q n+1 − 1
qi =
i=0
q−1
42
2. Arraydarstellung k- närer Bäume
h+1
k- närer Baum der Höhe h wird im Array mit k k−1−1 Elementen abgespeichert.
Das i-te Kind (1 ≤ i ≤ k) eines Knotens der beim j-ten Eintrag gespeichert ist, wird im
(k · j + i) Eintrag abgelegt.
inorder: besuche erst den linken Teilbaum unter der Wurzel, dann die Wurzel, dann ihren
rechten Teilbaum
preorder: besuche zuerst die Wurzel, dann dann links, dann rechts
T = (V, E)
in : V → N inorder Traversierung
h : V → N Höhenfunktion
'
V → R2
ϕ=
∪ → (in(u), h(u))
43
(2) Arithmetische Ausdrücke (auf ganzen Zahlen)
44
02. Dezember 2008
3.6.2 weitere Anwendungen: Spielbäume
TicTacToe
Beginnt der Kreis- Spieler in der Mitte, hat der Kreuz- Spieler acht verschiedene Möglichkeiten sein
Kreuz zu setzen.
Dann hat der Kreis- Spieler sieben Möglichkeiten. ...
Nehme als Root das leere Spielfeld. Der erste Nachfolger sind neun Knoten, alle Möglichkeiten für die
erste Belegung. Die Nachfolger dieser Knoten sind jeweils die acht Möglichkeiten, ein Kreuz zu setzen.
usw.
Es gibt besondere Knoten, bei denen das Spiel zu Ende ist. Dieser Knoten ist ein Blatt. Entweder, das
Spiel wird gewonnen oder es gibt ein Remis.
Zunächst werden alle Nachfolger der Wurzel erzeugt, erfüllen sie die Anforderung? Nun werden die
Kinder erzeugt, usw.
⇒ Breitensuche
1. Wurzel (r)
2. Kinder der Wurzel (seien diese w1 , w2 , w3 )
3. Kinder der Knoten aus 2. ; erst die Kinder von w1 , dann die Kinder von w2 , dann die Kinder
von w3
4. Deren Kinder. Nach Methodik von 3.
45
3.6.4 Tiefensuche in Bäumen
find(k,S) bestimme, ob k ∈ S
insert(k,S) füge k zu S hinzu
Bemerkung:
Vielfache Anwendungen!
1. Verkettete Liste
Platzbedarf θ(|S|)
Laufzeit:
insert θ(1) ggf. θ(|S|)
find θ(|S|)
delete θ(1) falls falls Zeiger in die Liste zeigt
sonst θ(|S|)
2. Hashing (Streuspeicherung)
46
04. Dezember 2008
3.7.2 Implementierung durch Hashing
U Universum
S⊂U
h1 : U → N
h2 : N → [1, . . . N ]
h2 (n) = 1 + (n mod 4)
3.7.3 Hashcodes
!∗
1. Zeichenketten s = s1 . . . sk ∈
(a) Länge
!0 ! !
(b) h! (s) = h1 (si )| | {σ0 , . . . , σl }
'!
0 →N
wobei h1 =
σi 1→ i
z.B.: ASCII
s = AFFE
!
| | = 256, h1 (A) = 65 , h2 (F ) = 70 , h3 (E) = 69 , h1 (s) = (((65 · 256 + 70) · 256) + 70) · 256 + 69
2. Floatingpoint- Zahlen
Kompressionsverfahren
Idee: h2 soll S “möglichst geleichmäßig” auf [1, . . . N ] aufteilen. Typischerweise ist N eine Primzahl
Bsp.:
1. h2 (x) = 1 + (x mod N )
47
Hashing mit Verkettung
U Universum
|U | = u
S ⊂ U, |S| = n
Analyse:
48
Laufzeit (für Eintrag mit Schlüssel k)
hängt ab von
Falls h in O(n) Zeit ausgewertet werden kann, benötigen alle Operationen θ(1 + |Cs (k)|) Zeit.
1 1
P r(S = V ) = pv = . /=
u |W |
n
W = {S ⊂ U | |S| = n}
Für k ∈ U fest betrachten wir Cs (k) Zufallsvariable und interessieren uns für
E [CS (K)] =
& 1
pv |Cv (k)| =
|W |
v∈W
!
v∈W [CS (K)]
Beweis:
49
'
& & 1 y∈S
[CS (K)] = 1= iS (y) mit iS (y) =
y∈S, h(k)=h(y) y∈U, h(k)=h(y)
0 sonst
Damit
1 &
E [CS (K)] = · [CV (K)]
|W |
V ∈W
1 & &
= · · v(y)
|W |
V ∈W y∈U, h(k)=h(y)
pv
$%"#
& & 1
= · v(y)
|W |
V ∈W y∈U, h(k)=h(y)
,u−1-
n
E[iS (y)] = 1 · P r(iS (y) = 1) + 0 · P r(is (y) = 0) = P r(y ∈ S) = n−1
, n- =
u
u
(*)
50
09. Dezember 2008
3.7.4 Zufallsexperiment
,U -
S∈ n wird zufällig (unter Gleichverteilung gewählt)
Analyse Zufallsvariable (für x ∈ U )
|CS (x)| = |{y ∈ S|h(x) = h(y)}| (s.o.)
Fortsetzung von (*)
& n
=⇒ E [CS (x)] =
u
y∈U, h(k)=h(y)
n &
= · 1
u
y∈U, h(k)=h(y)
n
= · |CS (x)| = |{y ∈ S|h(x) = h(y)}|
u
Def.:
51
(a) mit N = θ(n) erhalten wir θ(1) (erwartete) Zugriffszeit und θ(n) Speicher.
(unter den bekannten Annahmen)
(b) Falls n nicht bekannt ist, kann durch Verdoppeln, bzw. Halbieren der Tabellengröße (inkl.
Umkopieren) θ(1) amortisierte erwartete Laufzeit bei θ(n) Platz erreicht werden.
Analyse:
&
E [|Cx (h)|] = E δxy (h)
y∈S
&
= [δxy (h)]
y∈S
&
= (P r (h(x) = h(y)))
y∈S
! #
|{h ∈ H|h(x) = h(y)}| 1
mit P r(h(x) = h(y)) = =
" $
|H| N
& 1 n
E [|Cx (h)|] ≤ =
N N
y∈S
Def.:
U
Eine Menge H ⊂ {0, . . . , N − 1} von Hashfunktionen heißt universell, falls ∀x, y ∈ U mit x 6= y
|H|
|{h ∈ H|h(x) = h(y)}| ≤
N
52
Damit:
Die erwartete Zugriffszeit für Hashing mit Verkettung bei zufälliger Wahl von h aus einer universellen
Familie von H- Funktionen bei der Verkettung
3 n 4 einer (jeder!) (festen) n- elementigen Teilmenge S ⊂ U
in einer Tabelle mit N Einträgen ist θ 1 bei θ(n + N + |h| ) Speicher.
N "#$%
Platzbedarf, um h zu codieren
9 :
r+1
Dann ist H = ha |a ∈ {0, . . . , N − 1} universell.
Bemerkung:
(a) Zum Abspeichern von h(a0 ,...,ar ) wird θ(r) Platz benötigt.
(b) Zum Berechnen von h(a0 ,...,ar ) (x0 , . . . xr ) wird θ(r) Zeit benötigt.
53