Download Binary Search: An Efficient Algorithm for Array Searches and more Exercises Data Structures and Algorithms in PDF only on Docsity!
Binary Search
Searching an Array
Linear Search on Sorted Arrays
Stop early if we find an element greater than x
Worst case complexity: still O(n)
o e.g., if x is larger than any element in A
int search(int x, int[] A, int n)
//@requires n == \length(A);
//@requires is_sorted(A, 0, n);
/*@ensures (\result == - 1 && !is_in(x, A, 0, n))
|| (0 <= \result && \result < n && A[\result] == x); @*/
for (int i = 0; i < n; i++) {
if (A[i] == x) return i;
if (x < A[i]) return - 1;
//@assert A[i] < x;
return - 1;
Loop invariants
omitted
Can we do Better on Sorted Arrays?
Look in the middle!
o compare the midpoint element with x o if found, great! o if x is smaller, look for x in the lower half o if x is bigger, look for x in the upper half
This is
Binary Search
Why better?
o we are throwing out half of the array each time!
with linear search, we were throwing out just one element!
o if array has length n , we can halve it only log n times
Piece of cake!
More of a Cautionary Tale
Joshua Bloch finds a bug in Jon
Bentley’s definitive binary search!
o that Bentley had proved correct!!!
Went on to implementing several
searching and sorting algorithms
used in Android, Java and Python
o e.g., TimSort
Read more at
https://ai.googleblog.com/2006/06/extra-extra-read-all-
about-it-nearly.html
Joshua Bloch ,
- student of Jon Bentley
- works at Google
- occasionally adjunct prof. at CMU Joshua Bloch
Even More of a Cautionary Tale
Researchers find a bug in
Joshua Bloch’s code for
TimSort
o Implemented it in a language with contracts (JML – Java Modelling Language) o Tried to prove correctness using KeY theorem prover
Read more at
http://www.envisage-project.eu/proving-android-
java-and-python-sorting-algorithm-is-broken-and-
how-to-fix-it/
Some of the same contract
mechanisms as C
(and a few more)
(we borrowed our contracts of them)
Binary Search
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7 2 3 5 9 11 13 17
A:
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
Binary Search
A is sorted
Looking for
x = 4
find midpoint of A[0,7)
- ignore A[4,7)
- ignore also A[3]
find midpoint of A[0,3)
- ignore A[0,1)
- ignore also A[1]
find midpoint of A[2,3)
- ignore A[3,3)
- ignore also A[2]
nothing left!
- A[2,2) is empty (^10) • 4 isn’t in A
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7
A:^2 3 5 9 11 13
0 1 2 3 4 5 6 7 2 3 5 9 11 13 17
A:
Binary Search
Let’s look for
x = 11
At each step, we
o examine a segment A[lo, hi) o find its midpoint mid o compare x = 11 with A[mid]
find midpoint of A[lo,hi)
A[mid] < 11
- ignore A[lo,mid)
- ignore also A[mid]
find midpoint of A[lo,hi)
- index mid = 5
- A[mid] = 13
11 < A[mid]
- ignore A[lo,mid)
- ignore also A[mid]
find midpoint of A[lo,hi)
- index mid = 4
- A[mid] = 11
11 = A[mid]
- found!
- return 4 lo hi lo mid hi lo hi lo mid hi lo hi lo,mid hi
Implementing Binary Search
What do we Know at Each Step?
At an arbitrary iteration, the picture is:
These are candidate loop invariant:
o gt_seg(x, A, 0, lo): that’s A[0, lo) < x o lt_seg(x, A, hi, n): that’s x < A[hi, n) o and of course 0 <= lo && lo <= hi && hi <= n
A:
0 lo hi n … …
A[0, lo) < x x < A[hi, n)
Too small! If x is in A, Too big!
it’s got to be here
Adding Loop Invariants
int binsearch(int x, int[] A, int n)
//@requires n == \length(A);
//@requires is_sorted(A, 0, n);
/*@ensures (\result == - 1 && !is_in(x, A, 0, n))
|| (0 <= \result && \result < n && A[\result] == x); @*/
int lo = 0;
int hi = n;
while (lo < hi)
//@loop_invariant 0 <= lo && lo <= hi && hi <= n;
//@loop_invariant gt_seg(x, A, 0, lo);
//@loop_invariant lt_seg(x, A, hi, n);
return - 1;
0 ≤ lo ≤ hi ≤ n … … A[0, lo) < x x < A[hi, n)
Are the Loop Invariants Valid?
INIT
o lo = 0 by line 7 and hi = n by line 8
To show : 0 ≤ 0 by math
To show : 0 ≤ n by line 2 (preconditions) and \length
To show : n ≤ n by math
To show : A[0, 0) < x
To show : x < A[n, n)
by math (empty intervals)
PRES
Trivial
o body is empty o nothing changes!!!
- int binsearch(int x, int[] A, int n)
- //@requires n == \length(A);
- //@requires is_sorted(A, 0, n);
- /*@ensures (\result == - 1 && !is_in(x, A, 0, n))
- || (0 <= \result && \result < n && A[\result] == x); @*/
- {
- int lo = 0;
- int hi = n;
- while (lo < hi)
- //@loop_invariant 0 <= lo && lo <= hi && hi <= n;
- //@loop_invariant gt_seg(x, A, 0, lo);
- //@loop_invariant lt_seg(x, A, hi, n);
- {
- …
- }
- //@assert lo == hi;
- return - 1;
- }
from correctness
proof
0 ≤ lo ≤ hi ≤ n … … A[0, lo) < x x < A[hi, n)
Is binsearch Correct?
EXIT
INIT
PRES
Termination
o Infinite loop!
Let’s implement what
happens in a binary
search step
o compute the midpoint o compare its value to x
- int binsearch(int x, int[] A, int n)
- //@requires n == \length(A);
- //@requires is_sorted(A, 0, n);
- /*@ensures (\result == - 1 && !is_in(x, A, 0, n))
- || (0 <= \result && \result < n && A[\result] == x); @*/
- {
- int lo = 0;
- int hi = n;
- while (lo < hi)
- //@loop_invariant 0 <= lo && lo <= hi && hi <= n;
- //@loop_invariant gt_seg(x, A, 0, lo);
- //@loop_invariant lt_seg(x, A, hi, n);
- {
- …
- }
- //@assert lo == hi;
- return - 1;
- }