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.