Binäre Suche

Transcription

Binäre Suche
Binäre Suche
Algorithmus Binary Search bekommt als Eingabe ein sortiertes Feld A mit n Elementen
und einem Element a. Es gilt also A[1] ≤ A[2] ≤ · · · ≤ A[n]. Wir nehmen zunächst an, dass
n eine Zweierpotenz ist, d.h. n = 2p , für ein p ≥ 0. Der Algorithmus soll herausfinden, ob a
in A vorkommt.
Binary Search(A, a)
1
2
3
4
5
6
7
8
9
l←1
r←n
k←0
while l < r do
k ←k+1
m ← l+r−1
2
if A[m] < a then l ← m + 1
else r ← m
return A[l] = a
Korrektheit
Kommt a nicht in A vor, dann ist Binary Search korrekt, da dies am Ende durch den Test
in Zeile 9 sicher gestellt wird. Nehmen wir im Folgenden also an, dass a in A vorkommt. Wir
müssen zeigen, dass Binary Search dann a findet. Es gelten folgende Schleifeninvarianten
in Zeile 4:
(i) r − l + 1 = n/2k = 2p−k ,
(ii) A[l] ≤ a ≤ A[r].
Wir beweisen die Schleifeninvarianten durch Induktion über k: Die Variable k wird ansonsten
eigentlich nicht benötigt, sie ist nur zu Erklärungszwecken da.
Für k = 0 ist r − l + 1 = n − 1 + 1 = n = n/20 und A[1] ≤ a ≤ A[n]. Der Induktionsanfang gilt also. Sei nun k ≥ 0 und gelten die Invarianten für die Werte r, l und k. Wir
betrachten einen Schleifendurchlauf, Zeile 5 bis 8. Die neu berechneten Werte bezeichnen wir
zur Unterscheidung mit r0 , l0 und k 0 . Es gilt also k 0 = k + 1 nach Zeile 5 und m = l+r−1
nach
2
Zeile 6.
Fall 1: A[m] < a. Dann ist l0 = m+1 und r0 = r nach Zeile 7. Wir zeigen, dass die Invarianten
in diesem Fall auch für die neuen Werte gelten:
r0 − l0 + 1 = r − (m + 1) + 1 = r −
l+r−1
r−l+1
0
0
=
= n/2k+1 = n/2k = 2p−k .
2
2
Da r0 = r ist, gilt a ≤ A[r]. Da in Fall 1 gilt A[m] < a, ist auch A[l0 ] = A[m + 1] ≤ a.
Fall 2: A[m] ≥ a. Dann ist l0 = l und r0 = m nach Zeile 8. Wir zeigen, dass die Invarianten
wieder gelten:
r 0 − l0 + 1 = m − l + 1 =
l+r−1
r−l+1
0
0
−l+1=
= n/2k+1 = n/2k = 2p−k .
2
2
Da l0 = l ist, gilt A[l0 ] ≤ a. Da in Fall 2 gilt a ≤ A[m] und r0 = m, ist auch a ≤ A[r0 ].
Aus Bedingung (i) folgt, dass der in Zeile 6 berechnete Wert l+r−1 für l < r immer gerade
ist (und sich somit ohne Rest durch 2 teilen lässt) Es gilt nämlich l+r−1 = (r−l+1)+2l+2 =
2(2p−k−1 + l + 1).
Binary Search stoppt, wenn die Bedingung der while-Schleife nicht mehr erfüllt ist, wenn
also l = r gilt. Nach Bedingung (ii) gilt A[l] ≤ a ≤ A[r]. Folglich ist dann A[l] ≤ a ≤ A[l] und
somit A[l] = a. Binary Search gibt also in Zeile 9 die richtige Antwort.
Laufzeit
Algorithmus Binary Search vergleicht die Elemente von A mit a nur in Zeile 7 (abgesehen
vom Schluss in Zeile 9). Mit V (n) bezeichnen wir die Anzahl der Vergleiche die Binary
Search während des gesamten Ablaufs in Zeile 7 macht. Dies ist damit auch die Anzahl der
Schleifendurchläufe, und somit proportional zur Rechenzeit von Binary Search.
Am Anfang gilt r−l+1 = n. Gemäß der Invarianten (i) halbiert sich dieser Wert bei jedem
Schleifendurchlauf. Die Schleife wird abgebrochen wenn l = r gilt, also wenn r − l + 1 = 1 ist.
Folglich muss n/2k = 2p−k = 1 sein, und somit k = p. Da p = log n macht Binary Search
also insgesamt V (n) = log n Vergleiche.
Allgemeines n
Wenn n keine keine Zweierpotenz ist, ist der Ausdruck l+r−1
in Zeile 6 im Allgemeinen keine
2
ganze Zahl. Da m ein Index im Feld A ist, muss m auf jeden Fall ganzzahlig sein. Wir runden
den Ausdruck einfach auf die nächst kleinere ganze Zahl ab. D.h. wir ändern Zeile 6 wie folgt:
60
m ← l+r−1
2
Der Rest von Binary Search bleibt unverändert. Für die Korrektheit genügt es, die Schleifeninvariante anzupassen. Bedingung (ii) bleibt unverändert. Bedingung (i) wird zu:
(i0 ) r − l + 1 ≤ n/2k .
Der Beweis verläuft analog wie oben. Allerdings müssen wir mit auf- oder abgerundeten
Werten umgehen. Dabei benützen wir folgende Rechenregeln und Ungleichungen von deren
Richtigkeit man sich leicht überzeugen kann. Für x ∈ Q und m ∈ N gilt:
1. x − 1 < bxc ≤ x ≤ dxe < x + 1,
2. bxc + m = bx + mc,
x
3. dxe
2 ≤ 2 .
Im Fall 1, für A[m] < a, gilt:
r0 − l0 + 1 = r − (m + 1) + 1
l+r−1
l+r−1
r−l+1
=r−
≤r−
=
2
2
2
l
m
l
m
k
n/2
n
n
≤ k+1 = k0 .
≤
2
2
2
Im Fall 2, für A[m] ≥ a, gilt:
r 0 − l0 + 1 = m − l + 1
l+r−1
r−l+1
r−l+1 l n m
=
−l+1=
≤
≤ k0 .
2
2
2
2
Auch die Anzahl der Vergleiche im allgemeinen Fall können wir analog
zu oben abschätzen:
k
Am Ende muss wieder r − l + 1 = 1 gelten. Folglich muss n/2 = 1 sein. Dies gilt für
k = dlog ne. Im allgemeinen Fall macht Binary Search also insgesamt V (n) = dlog ne
Vergleiche.