二分查找是一个非常常用的查找方式,它的时间复杂度是O(log n)的,比顺序查找时间复杂度为O(n)要好的多,也非常简单,下面我们来讨论一下它的逻辑实现:
狭义上的二分要求我们的元素要先有序才行,广义上的二分我们以后有机会再讲,其实它的思想就是,每次取数组的一半,看中间的元素是否使我们所要寻找的,是,则返回该元素所在下标,不是,则看该元素与中间元素的大小比较,要是该元素比中间元素小,则寻找范围的上界变为中间元素下标减一,要是该元素比中间元素小,中额寻找范围的下界变为中间元素+1,其实就是按对数阶来去缩小我们所求答案的范围,比像顺序查找每次范围-1的算法要优良很多。(扩充:广义上的二分:其实二分查找不一定非得要元素有序才行,只需要满足我们所要求的结果一定存在或者不存在另外一半的范围中,从而达到把检索的范围按对数阶缩小的目的,来优化算法,具体事例,参见我的下篇博文)
一、非递归实现
//非递归方式二分查找,查找到返回该元素所在的坐标,查找不到返回-1
public static int binSearch(int num, int [] arr ){
int length = arr.length;
int begin = 0;
int end = length-1;
int mid;
while(end >= begin){
mid = end - (end - begin)/2;
if(num == arr[mid]){
return mid;
}else if(num < arr[mid]){
end = mid-1;
}else {
begin = mid + 1;
}
}
return -1;
}
二、递归实现
//递归实现
public static int binSearch(int num, int[] arr, int begin, int end){
//递归书写规范,第一步先写base case,也就是递归终止的条件
if(end < begin){
return -1;
}
int mid = end - (end - begin)/2;
if(num == arr[mid]){
return mid;
}else if(num < arr[mid]){
return binSearch(num, arr, begin, mid - 1);
}else if(num > arr[mid]){
return binSearch(num, arr, mid + 1, end);
}
return -1;
}
注意:写中间元素的时候写成int mid = end - (end - begin)/2;而不是int mid = (end + begin)/2,是因为后面这种写法很可能造成数组越界。
测试代码:
public static void main(String[] args) {
int [] arr = {1,5,7,9,16,55};
System.out.println("二分非递归查找:"+binSearch(55, arr));
System.out.println("--------------------");
System.out.println("二分递归查找:"+binSearch(55, arr, 0, arr.length - 1));
}
运行结果: