序列二分查找
二分查找是在有序序列上的快速查找方法,二分查找的时间复杂度为O(logn)O(logn)O(logn),现实中很多情形我们需要先排序,然后再查找指定元素,这里就会用到二分查找
二分查找非常简单,实现上分为递归实现和非递归实现,这里其实有些需要注意的点。
原理
我们先看下原理,在一个有序的序列a:{a1,a2,...,aN}a:\{a_1,a_2,...,a_N\}a:{a1,a2,...,aN}里面,假设开始和结束的位置分别是left=1left=1left=1和right=Nright=Nright=N,待查找的数据值为valuevaluevalue,我们首先取到序列中间的位置midmidmid和值a[mid]a[mid]a[mid],用这个值来与待查值比较,
① 如果相等value==a[mid]value == a[mid]value==a[mid],说明我们找到了待查值,返回找到的下标midmidmid;
② 如果待查值大于中间位置的值value>a[mid]value > a[mid]value>a[mid],说明待查值只可能在mid+1mid+1mid+1和rightrightright中即序列{amid+1,...,aright}\{a_{mid+1},...,a_{right}\}{amid+1,...,aright}找到,此时更新leftleftleft为mid+1mid+1mid+1,重新在left和left和left和right中即中即中即[left,right][left,right][left,right]$中找;
③ 如果待查值小于中间位置的值,说明待查值只可能在leftleftleft和mid−1mid-1mid−1的的序列{aleft,...,amid−1}\{a_{left},...,a_{mid-1}\}{aleft,...,amid−1}中取到,此时更新rightrightright为mid−1mid-1mid−1,重新在leftleftleft和rightrightright即[left,right][left,right][left,right]中查找;
什么时候结束呢,当找到待查值时当然结束,如果没有找到待查值,最后会在[index,index+1][index,index + 1][index,index+1],mid=indexmid = indexmid=index,然后比较大小,会在[index,index][index,index][index,index]或者[index+1,index+1][index + 1, index + 1][index+1,index+1]中找,如果在[index,index][index,index][index,index]没有找到,此时会在[index+1,index][index + 1,index][index+1,index],或者[index,index−1][index,index - 1][index,index−1]去找,那么结束条件就是left>rightleft>rightleft>right
递归实现
int binarySearch(int *a, int left, int right, int value) {
if (left > right) {
return -1;
}
int mid = (left + right) / 2;
if (a[mid] == value) {
return mid;
} else if (a[mid] < value) {
left = mid + 1;
binarySearch(a, left, right, value);
} else {
right = mid - 1;
binarySearch(a, left, right, value);
}
}
非递归实现
二分查找改为非递归实现,需要一个while循环,循环退出条件和递归一样
int binarySearch(int *a, int left, int right, int key){
int mid;
while (left <= right){
mid = (left + right) / 2;
if(a[mid] == key){
return mid;
}else if(a[mid] < key){
left = mid + 1;
}else{
right = mid - 1;
}
}
return -1;
}