Introduction
The sequential search works on an unsorted array and runs in O(n) time. But if the array is sorted, it can be done much more efficiently in O(log2n) time though a divide and conquer algorithm known as binary-search.
How it works
The algorithm is very simple. Given a sorted array, array[0:n−1], and a serach key, the algorithm starts comparing the search key against the middle element of the array, array[m]. Then it follows these steps.
- if KEY=array[m], simply return m.
- if KEY>array[m], recursively search through the right half othe array.
- if KEY<array[m], recursively search through the left half othe array.
As we can see, after one operation, the size is reduced to 2n. After a second operation, the size is reduced to 4n and so on. So in the worst case scenario, the algorithms will make log2n comparisons. Here is the code below.
Algorithm
def binary_search(array:list,left:int, right:int, key:int)->int:
if left >= right:
return -1
m = int((left+right)/2)
if key == array[m]:
return m
elif key > array[m]:
return binary_search(array, left+1, right, key)
return binary_search(array,left,m-1, key )
Analysis for special case
when n=2k,
we will combine both key comparisons as one single comparison. That is because they are between the same pair of elements. Under the hood(assembly), the machine will probably do some optimization to count them as a single operation, thus we will consider them to be one. In that case
f(n)={1,1+f(2n)n=1n≥2 Solving this by repeated substitutions, we will obtain:
f(n)=1+f(2n)f(n)=1+1+f(4n)f(n)=1+1+1+f(8n)f(n)=1+1+1+1+f(16n)f(n)=4+f(24n)f(n)=k+f(2kn)f(n)=k+1f(n)=log2n+1 Analysis for general n
for the general case, the size of the recursive call is at most ⌊2n⌋. So,
f(n)={1,1+f(⌊2n⌋)n=1n≥2 We will prove by induction that the solution is f(n)=⌊log2n⌋+1
base case, n=1 from the recurrence, f(1)=1 and the claimed solution is f(n)=⌊log21⌋+1=1, so the basic is correct.
induction step. Any n can be expressed as follows, for some integer k.
2k≤n<2k+1 This means that ⌊log2n⌋=k. Also,
2k−1≤⌊2n⌋<2k Thus, ⌊log2⌊2n⌋⌋=k−1. To prove the claimed solution for any n≥2, suppose the solution is correct for all smaller values. That is,
f(m)=⌊logm⌋+1,∀m<n In particular, for m=⌊2n⌋,
f(⌊2n⌋)=⌊log2⌊2n⌋⌋+1=(k−1)+1=k=⌊log2n⌋ Then,
f(n)=f(⌊2n⌋)+1=k+1=⌊log2n⌋+1