序列二分查找
二分查找是在有序序列上的快速查找方法,二分查找的时间复杂度为
O
(
l
o
g
n
)
O(logn)
O(logn),现实中很多情形我们需要先排序,然后再查找指定元素,这里就会用到二分查找
二分查找非常简单,实现上分为递归实现和非递归实现,这里其实有些需要注意的点。
原理
我们先看下原理,在一个有序的序列 a : { a 1 , a 2 , . . . , a N } a:\{a_1,a_2,...,a_N\} a:{a1,a2,...,aN}里面,假设开始和结束的位置分别是 l e f t = 1 left=1 left=1和 r i g h t = N right=N right=N,待查找的数据值为 v a l u e value value,我们首先取到序列中间的位置 m i d mid mid和值 a [ m i d ] a[mid] a[mid],用这个值来与待查值比较,
① 如果相等 v a l u e = = a [ m i d ] value == a[mid] value==a[mid],说明我们找到了待查值,返回找到的下标 m i d mid mid;
② 如果待查值大于中间位置的值 v a l u e > a [ m i d ] value > a[mid] value>a[mid],说明待查值只可能在 m i d + 1 mid+1 mid+1和 r i g h t right right中即序列 { a m i d + 1 , . . . , a r i g h t } \{a_{mid+1},...,a_{right}\} {amid+1,...,aright}找到,此时更新 l e f t left left为 m i d + 1 mid+1 mid+1,重新在 l e f t 和 left和 left和right 中 即 中即 中即 [ l e f t , r i g h t ] [left,right] [left,right]$中找;
③ 如果待查值小于中间位置的值,说明待查值只可能在 l e f t left left和 m i d − 1 mid-1 mid−1的的序列 { a l e f t , . . . , a m i d − 1 } \{a_{left},...,a_{mid-1}\} {aleft,...,amid−1}中取到,此时更新 r i g h t right right为 m i d − 1 mid-1 mid−1,重新在 l e f t left left和 r i g h t right right即 [ l e f t , r i g h t ] [left,right] [left,right]中查找;
什么时候结束呢,当找到待查值时当然结束,如果没有找到待查值,最后会在 [ i n d e x , i n d e x + 1 ] [index,index + 1] [index,index+1], m i d = i n d e x mid = index mid=index,然后比较大小,会在 [ i n d e x , i n d e x ] [index,index] [index,index]或者 [ i n d e x + 1 , i n d e x + 1 ] [index + 1, index + 1] [index+1,index+1]中找,如果在 [ i n d e x , i n d e x ] [index,index] [index,index]没有找到,此时会在 [ i n d e x + 1 , i n d e x ] [index + 1,index] [index+1,index],或者 [ i n d e x , i n d e x − 1 ] [index,index - 1] [index,index−1]去找,那么结束条件就是 l e f t > r i g h t left>right left>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;
}