Fibonacci-Suche - Zentrum für Angewandte Informatik der

Werbung
Fibonacci-Suche
Grundidee wie bei der Binärsuche, aber andere Aufteilung
Fibonacci-Zahlen:
Informatik I
• F0 = 0
Einführung
• F1 = 1
• Fm = Fm−1 + Fm−2 für m ≥ 2
Rainer Schrader
vereinfachende Annahme: Sei n = Fm − 1 für geeignetes m.
Beispiel für (m = 8):
Zentrum für Angewandte Informatik Köln
24. Mai 2005
1
8 = i = Fm−2
20 = n = Fm − 1
12
= Fm−1 − 1
Elemente
7
= Fm−2 − 1
Elemente
2 / 43
1 / 43
Fibonacci-Suche
Fibonacci-Suche
Beispiel für (m = 8):
1
1
8 = i = Fm−2
7
= Fm−2 − 1
Elemente
8 = i = Fm−2
20 = n = Fm − 1
20 = n = Fm − 1
12
= Fm−1 − 1
Elemente
7
= Fm−2 − 1
Elemente
12
= Fm−1 − 1
Elemente
Suche im rechten Bereich:
Fibonacci-Suche
1
5 = i = Fm−3
12 = Fm−1 − 1
Sei n = Fm − 1 für geeignetes m ≥ 2.
•
•
setze i = Fm−2
7
= Fm−2 − 1
Elemente
4
= Fm−3 − 1
Elemente
vergleiche den zu suchenden Schlüssel k mit A(i ):
• ist A(i ) = k : Suche erfolgreich
• ist A(i ) > k : durchsuche den linken Bereich mit Fm−2 − 1 Elementen
Suche im linken Bereich:
• ist A(i ) < k : durchsuche den rechten Bereich mit Fm−1 − 1 Elementen
1
3 = i = Fm−4
2
= Fm−4 − 1
Elemente
3 / 43
7 = Fm−2 − 1
4
= Fm−3 − 1
Elemente
4 / 43
Fibonacci-Suche
Fibonacci-Suche
fibonacci_search(A, m, k)
//
sucht nach Position mit Schlüssel k
//
im Bereich A[1..n] mit (n = F(m)-1),
//
liefert 0, falls nicht vorhanden
programmtechnische Umsetzung
Sei n = Fm − 1 für geeignetes m ≥ 2.
•
•
wir speichern ein Paar (f1 , f2 ) = (Fm−3 , Fm−2 )
•
Suche im rechten Intervall der Länge Fm−1 − 1:
pos = -1; f1 = F(m-3); f2 =
while (pos < 0) do
if (k > A(i))
//
if (f1 = 0)
//
then pos = 0
else
i = i + f1
t = f1
f1 = f2 - f1
f2 = t
end if
//
else if (k < A(i))
if (f2 = 1)
//
then pos = 0
else
i = i - f1
f2 = f2 - f1
f1 = f1 -f2
end if
else pos = i
//
end if
return pos
wir testen an der Stelle f2
• ist f1 = 0 :
• ; Fm−3 = 0, Fm−2 = 1
• ; Fm−1 − 1 = Fm−3 + Fm−2 − 1 = 0, d.h. die Suche bricht ab.
• andernfalls merken wir uns (f10 , f20 ) = (Fm−4 , Fm−3 ) = (f2 − f1 , f1 )
•
Suche im linken Intervall der Länge Fm−2 − 1 :
• ist f2 = 1, so ist Fm−2 − 1 = 0, d.h. die Suche bricht ab.
• andernfalls merken wir uns (f10 , f20 ) = (Fm−5 , Fm−4 ) = (2f1 − f1 , f2 − f1 )
F(m-2); i = f2;
Durchsuche den oberen Bereich
nicht vorhanden
Dursuche den unteren Bereich
nicht vorhanden
gefunden
7 / 43
5 / 43
Analyse der Fibonacci-Suche
•
•
•
•
Analyse der Fibonacci-Suche
wir starten mit einem Intervall der Länge Fm − 1
das nächste Intervall hat eine Länge von höchstens Fm−1 − 1
...
•
Damit ist Fm ≈ c · 1.618m mit einer Konstanten c.
•
Für n + 1 = Fm ≈ c · 1.618m benötigen wir maximal m Vergleiche
•
damit folgt:
Cmax (n) = Θ(log1.618 (n + 1)) = Θ(log2 n).
damit benötigen wir höchstens m Schlüsselvergleiche
•
Lemma
√
√
√
1 h“ 1 + 5 ”m “ 1 − 5 ”m i D 1 1 + 5 m E
Fm = √
−
= √ (
) .
2
2
2
5
5
Es gilt auch (ohne Beweis):
Cavg (n) = Θ(log2 n).
Beweis per Induktion.
•
Das ist die gleiche Größenordnung wie bei der Binärsuche, aber hier haben wir
keine Divisionen, nur Additionen und Subtraktionen.
•
genauer: keine Shiftoperationen.
Hierbei steht hi für kaufmännisches Runden.
8 / 43
9 / 43
Exponentielle Suche
Exponentielle Suche
Wenn n sehr groß ist, kann es sinnvoll sein, zunächst einen Bereich zu bestimmen, in dem ein gegebener Schlüssel liegen muß, falls er vorhanden ist.
Idee der exponentiellen Suche
exponential_search(A, n, k)
// suche nach Position mit Schlüssel k im Bereich A[1..n]
• wir verdoppeln in jedem Schritt den Suchbereich
• bis wir ein Intervall gefunden haben mit A( 2i ) < k ≤ A(i )
• in diesem Intervall suchen wir binär weiter.
1
2
4
8
if ((k<A(1) or k>A(n)))
return 0
else
i = 1
while ((k>A(i)) und (i<n)) do i = i + i
if (i>n) i = n
return binary_search(A,i/2,i,k)
16
12 / 43
10 / 43
Analyse der exponentiellen Suche
Interpolationssuche
•
Annahme: alle Schlüssel sind verschieden, positiv und ganzzahlig.
•
•
•
; Schlüssel wachsen mindestens so schnell wie die Indizes der Elemente
•
; wird in der while-Schleife d -mal verdoppelt, so gilt
Sucht man im Telefonbuch den Namen „Ackermann“, so wird man vorne
aufschlagen, bei „Knuth“ eher in der Mitte.
j
m
Binärsuche: m = l + 21 (r − l )
Unter der Annahme der gleichmäßigen Verteilung der Schlüssel ersetzen wir
durch die erwartete Position des Suchschlüssels
2d −1 ≤ A(2d −1 ) < k < A(2d )
•
•
•
•
•
—
m= l+
; d < 1 + log k = Θ(log k ) Vergleiche.
1
2
k − A(l )
(r − l ) .
A(r ) − A(l )
der Suchbereich enthält dann höchstens 2d −1 < k Schlüssel
; Θ(log k ) Vergleiche in binary_search im worst case.
Es lässt sich zeigen:
die Gesamtlaufzeit beträgt somit Θ(log k ).
Satz
sinnvoll, wenn k n gilt.
Sind die n Schlüssel unabhängig und gleichverteilt aus einem Intervall I, so beträgt die
mittlere Suchzeit O(log log n).
Aber: worst-case Θ(n), schlechter als binäre Suche.
13 / 43
14 / 43
quadratische Binärsuche
quadratische Binärsuche
Versuch, unter Beibehaltung der guten mittleren Laufzeit die worst-case-Laufzeit zu verbessern.
setze l := 0, r := n + 1 und rufe quadratische Binärsuche(A,k,l,r) auf.
quadratische Binärsuche
quadratische Binärsuche(A,k,l,r)
•
•
•
•
•
seien wie vorher A(1) < . . . < A(n)
führe lineare Suche auf diesen Subintervallen duch und bestimme das
Subintervall, in dem x liegen müßte
(3) ist k > A(aktuell ), setze l := aktuell + 1
•
wende das Verfahren rekursiv auf dieses Subintervall an.
√
√
(5) bestimme durch lineare Suche ein i mit A(l + d(i − 1) n e) ≤ k ≤ A(l + di n e)
zusätzlich A(0) < A(1), A(n + 1) > A(n)
k −A(l )
(1) setze aktuell := l + d A(r )−A(l ) · (r − l )e
führe einen Schritt der Interpolationssuche aus
teile das verbleibende Suchintervall in Subintervalle der Größe
√
(2) ist k = A(aktuell ), stop.
n auf
(4) ist k < A(aktuell ), setze r := aktuell − 1
(6) wende Verfahren rekursiv an auf das Intervall
√
[l + d(i − 1) n e,
√ n
√ n
√ n
√ n
l + di
√
n e].
√ n
15 / 43
16 / 43
quadratische Binärsuche
quadratische Binärsuche
Satz
Unter der obigen Voraussetzung betragen die mittleren Kosten Tavg (n) der
quadratischen Binärsuche O(log log n).
Es läßt sich zeigen:
Lemma
Beweis:
√
Es gilt: Tavg (1) ≤ 1, Tavg (2) ≤ 2 und Tavg (n) ≤ C + Tavg ( n) für n ≥ 3.
Seine die Schlüssel unabhängig und gleichverteilt über (A(0), A(n + 1)).
Dann ist die mittlere Anzahl C der Vergleiche pro Programmaufruf der
quadratischen Binärsuche höchstens 3.
Wir zeigen per Induktion Tavg (n) ≤ 2 + C log log n:
Tavg (n + 1) ≤ C + Tavg (
1
• das Verfahren
findet im Mittel nach drei Schritten das Intervall der
√
Größe
p
n + 1)
= C + 2 + C log log((n + 1) 2 )
n, in dem k liegen müßte.
1
log(n + 1)
2
= 2 + C log log(n + 1)
= C + 2 + C log
• Daraus läßt sich die mittlere Laufzeit abschätzen:
√
1
1
Im schlimmsten Fall beträgt die Suchzeit n 2 + n 4 + . . . = O( n) Einheiten.
17 / 43
18 / 43
quadratische Binärsuche
exponentielle und binäre Suche
setze l := 0, r := n + 1 und rufe quadratische Binärsuche(A,k,l,r) auf.
2. Versuch, unter Beibehaltung der guten mittleren Laufzeit die worst-case-Laufzeit zu
verbessern.
quadratische Binärsuche(A,k,l,r)
exponentielle und binäre Suche
•
•
•
•
•
•
•
k −A(l )
(1) setze aktuell := l + d A(r )−A(l ) · (r − l )e
seien wie vorher A(1) < . . . < A(n)
(2) ist k = A(aktuell ), stop.
zusätzlich A(0) < A(1), A(n + 1) > A(n)
(3) ist k > A(aktuell ), setze l := aktuell + 1
führe einen Schritt der Interpolationssuche aus
(4) ist k < A(aktuell ), setze r := aktuell − 1
zerlege
√
√ Suchintervall in Subintervalle der Größe
√ das√verbleibende
n, 2 n, 4 n, . . . 2i n auf
√
teile das verbleibende Suchintervall in Subintervalle der Größe n auf
(5) bestimme:
√
√
S(l + 2i −1 n) < k ≤ S(l + 2i n).
√
√
(6) auf dem Intervall [l + 2i −1 n, l + 2i n] bestimme j durch binäre Suche mit
führe binäre Suche auf diesen Subintervallen duch und bestimme das
Subintervall, in dem x liegen müßte
√
√
S(l + (j − 1) n) < k ≤ S(l + j n).
wende das Verfahren rekursiv auf dieses Subintervall an.
√
√
(7) Wende Verfahren rekursiv auf das Intervall [l + (j − 1) n, l + j n] an
19 / 43
20 / 43
exponentielle und binäre Suche
selbstorganisierende Listen
Szenario:
• Datenstruktur: verkettete, unsortierte Listen
• wiederholte Suchanfragen
• unterschiedliche Häufigkeiten für die Schlüssel
Satz
Unter der obigen Voraussetzung gilt für die exponentielle und binäre Suche:
•
•
die Anzahl der Vergleiche im schlechtesten Fall ist O(log n)
die Anzahl der Vergleiche im Mittel ist O(log log n) ( da log i ≤ i )
• organisiere Liste so um, dass
• häufige Anfragen am Anfang der Liste
21 / 43
22 / 43
selbstorganisierende Listen
Suchverfahren
Stragien:
•
zur Suche haben wir bisher lediglich Vergleichsoperationen auf den Schlüsseln
zugelassen
•
•
wir wollen jetzt arithmetische Operationen auf den Schlüsseln erlauben,
Bei jeder Anfrage an einen Schlüssel:
• vertausche Listenelement mit Element davor, oder
• erhöhe einen Anfragenzähler und sortiere nach fallendem Zähler, oder
• setze Element an die Spitze der Liste.
um daraus die mögliche Position des Datums zu berechnen.
24 / 43
23 / 43
Hashverfahren
Anwendungen: Symboltabellen für Compiler (Schlüssel: Bezeichner
(Identifiers))
• Bezeichner dürfen 80 Zeichen lang sein
• das erste Zeichen muss ein Buchstabe sein
• die folgenden Zeichen können auch Sonderzeichen sein
Hashverfahren
• zulässige Bezeichner: 26 · 3779
• davon kommen in einem Programm nur k ≪ 26 · 3779 vor
gesucht: Datenstruktur,
• die Suchen, Einfügen, Entfernen effizient unterstützt
• deren Größe nur von k abhängt
25 / 43
26 / 43
Hashverfahren
Hashverfahren
Idee: „verallgemeinerte Felder“
gegeben: Datensätze
•
•
•
•
• Datensätze werden über Schlüssel identifiziert
• zu unterstützende Operationen: Suchen, Einfügen, Entfernen
• bisher: lineare geordnete Listen
• Suchen mittels Schlüsselvergleichen
• jetzt:
wir verwenden ein Feld T (m) (Hashtabelle)
m ist die Größe der Hashtabelle
dem Schlüssel k wird eine Adresse h(k ) in T zugeordnet
aber 2 Schlüssel können auf dieselbe Adresse abgebildet werden
(Kollisionen)
Kollisionen:
• Adressen werden durch eine arithmetische Berechnung ermittelt
• jeder Schlüssel k wird über eine Adresse h(k ) angesprochen
• müssen behandelt werden,
• sollen möglichst selten auftreten,
• sollen möglichst effizient aufgelöst werden.
28 / 43
27 / 43
Hashverfahren
Hashverfahren
Szenario
• die Schlüssel entstammen einer (im allgemeinen großen) Menge U
Inhaltsangabe:
(Universum)
•
•
•
•
• Die Wahl der Hashfunktion
• Kollisionsbehandlungen
29 / 43
die zu speichernden Schlüssel K bilden eine Teilmenge von U
üblicherweise ist |K | |U |
die Größe m der Hashtabelle wird vorab festgelegt, oft ist m ≤ |K |
ebenso die Hashfunktion h : U → {0, . . . m − 1}
30 / 43
Direkte Adressierung
Direkte Adressierung
Illustration: (m = 10)
der einfachste Fall:
(alle möglichen Schlüssel)
6
1
•
•
•
•
•
•
5
8
T (k ) zeigt auf einen Datensatz mit Schlüssel k
suche(T,k):
gib T (k ) zurück
füge_ein(T,x):
lösche(T,x):
2
10
2
verwende Feld T [0, . . . , m − 1] (Adresstabelle)
10
3
K
(aktulle Schlüssel)
Implementierung der Operationen:
0
10
U
• Alle Schlüssel sind verschieden.
• U = {0, 1, . . . , m − 1}.
5
8
3
7
alle diese Operationen benötigen im worst-case O(1) Zeit.
0
9
2
3
4
5
7
8
9
10
T (x .key ) = nil
1
6
10
10
T (x .key ) zeigt auf x
4
32 / 43
31 / 43
Hashtabellen
Hashtabellen
Illustration:
• im Allgemeinen gilt jedoch: |K | |U |
0
U
1
• Ziele:
h(k1 )
• Θ(|K |) Speicherplatz
• Suche im Durchschnitt in Θ(1) Zeit
h(k4 )
K
k3
k1
• Methode: Benutzung einer Hashfunktion
h(k2 ) = h(k5 )
k4
h(k3 )
k2
h : U → {0, 1, 2, . . . , m − 1}
k5
33 / 43
m−1
34 / 43
Hashtabellen
Wahl der Hashfunktion
•
•
•
•
•
Probleme:
Was zeichnet eine gute Hashfunktion aus?
Ziel: Die Hashadressen sollen gleichverteilt in {0, 1, . . . , m − 1} sein.
Die Verteilung der Adressen hängt ab von der Verteilung der Schlüssel.
Sei p(k ) die Wahrscheinlichkeit, daß Schlüssel k ∈ U vorkommt.
Gleichverteilungsziel:
(1) Wie soll man die Hashfunktion wählen?
X
(2) Wie geht man mit Kollisionen um?
p(k ) =
k : h(k )=j
1
m
für j = 0, 1, . . . , m − 1.
• Beispiel: Schlüssel sind reelle Zahlen, unabhängig gleichverteilt im
Intervall [0, 1). Dann erfüllt
h(k ) = bkmc
das Gleichverteilungsziel.
• Problem: Im Allgemeinen kennen wir p(k ) nicht.
35 / 43
36 / 43
Wahl der Hashfunktion
Wahl der Hashfunktion
Divisionsmethode
h(k ) = k mod m
• Generalannahme: Die Schlüssel sind nichtnegative ganze Zahlen.
Eigenschaften
• Es ist immer möglich, Schlüssel so zu interpretieren, z.B.
(1) h(k ) kann schnell berechnet werden.
• Charakterstrings: Jedem Zeichen entspricht im ASCII-Code eine
Zahl im Bereich [0, . . . , 127], z.B.
• p=
ˆ 112,
t=
ˆ 116
⇒
(2) Die richtige Wahl von m (Tabellengröße) ist sehr wichtig.
pt =
ˆ 112 × 128 + 116 = 14452
Beispiele
• Aufteilung in männlich/weiblich
• Aufteilung nach Wochentagen der Geburt
• Aufteilung nach Geburtstagen
37 / 43
38 / 43
Divisionsmethode
Divisionsmethode
zu (2): Man sollte vermeiden:
• m = 2i : alle bis auf die letzten Binärziffern werden ignoriert.
• m = 10i : analog bei Dezimalzahlen.
• m = r i : analog bei r -adischen Zahlen.
allgemein gilt:
• sei A ein Alphabet mit den Buchstaben 0, . . . , 2p − 1
• sei k eine Zeichenkette über A, k 0 eine Permutation von k
• dann ist: k ≡ k 0 mod 2p .
• m = r i ± j für kleines j :
• z.B. m = 27 − 1 = 127:
• pt = (112 · 128 + 116) mod 127 = 14452 mod 127 = 101
Übungsaufgabe: warum?
• tp = (116 · 128 + 112) mod 127 = 14960 mod 127 = 101
• dasselbe passiert, wenn in einer längeren Zeichenkette zwei
Buchstaben vertauscht werden
39 / 43
40 / 43
Divisionsmethode
Wahl der Hashfunktion
Multiplikationsmethode
i
• Gute Wahl: Primzahl m, die kein r ± j , j klein, teilt.
Sei 0 < A < 1. Setze:
h(k ) = bm(k · A mod 1)c = bm (k · A − bk · Ac)c
|
{z
}
• Praktisch bewährt
∈[0,1)
• Beispiel: Die Hashtabelle soll ca. 1000 Einträge aufnehmen, die
Schlüssel sind Zeichenketten, interpretiert als 2-adische Zahlen.
Eigenschaften
Gute Wahl: m = 701, da 29 = 512 und 210 = 1024.
(1) Die Wahl von m ist unkritisch.
(2) Wir erhalten eine gleichmäßige Verteilung für U = {1, 2, . . . , n} bei
einer guten Wahl von A.
41 / 43
42 / 43
Multiplikationsmethode
zu (2): Irrationale Zahlen sind eine gute Wahl, denn:
Satz
Sei ξ eine irrationale Zahl. Plaziert man die Punkte
ξ − bξc, 2ξ − b2ξc, . . . , nξ − bnξc
in das Intervall [0, 1], dann haben die n + 1 Intervallteile höchstens drei
verschiedene Längen.
Außerdem fällt der nächste Punkt
(n + 1)ξ − b(n + 1)ξc
in einen der größten Intervallteile.
43 / 43
Herunterladen