二分查找法
对一个已排序数组进行查找,查找方法是每次取数组中间位置的数和当前查找数比较,如果查找数等于当前这个中间数,则找到结果直接返回(这里不考虑数组中有多个相同的查找数的情况,后续章节会讲解)。查找数小于中间数,则去中间数左侧继续查找,查找数大于中间数,则去中间数右侧查找,不管继续在左侧查找还是右侧查找,都重复以上操作,直到找到结果或发现数组中不存在查找数。
上面写的不直观,我们举个例子,例如当前数组:{1,2,5,6,7,8,9,15,22,26,36}
数组已经排序了,我们要查找值为22的数,按照逻辑,我们取数组中间位置的数和查找数进行比较,数组中间数为下标为5的数,值为8,8<22,则从下标6到数组结束的区间,继续取中间位置的比较。
这里有高低位的概念,从下标为5之后的元素到数组结尾继续取中间数,那么低位下标是6,高位下标为10,我们取中间数下标为:low+(high-low)/2=8,下标为8的值刚好是22,那么查找结束,返回值为8。
代码:
public static void main(String[] args) {
int[] arrs = {1,2,5,6,7,8,9,15,22,26,36};
System.out.println("查找数的下标为:"+ search(arrs, 22));
}
public static int search(int[] arrs, int x) {
int low = 0, high = arrs.length-1;
while(low<=high) {
//不使用(low+high)/2,是因为low+high有可能溢出
int mid = low+(high-low)/2;
if(arrs[mid] == x) {
return mid;
}
//这里的的low和high的复制如果直接复制mid,
//可能造成死循环,当查询的值不在数组中,就永远无法终止循环
if(arrs[mid] > x) {
high = mid-1;
}
if(arrs[mid] < x) {
low = mid+1;
}
}
return -1;
}
输出:
查找数的下标为:8
二分查找法的时间复杂度O(logn)。
但是二分查找是有使用条件的。
1、查找的数据结构必须是数组,因为通过高低位计算快速定位到中间位置,所以如果使用链表,原来的O(1)复杂度找到中间位置,就变成了O(n),时间复杂度就不是O(logn)了。
2、查找的数组必须是已经排序的有序数组,如果数组是无序的,则需要先排序。
3、二分查找不适用于数据量过大的场景,因为二分查找基于数组,数组那么久需要内存中一段连续的空间,如果数据量过大,那么就需要非常大的连续内存空间,例如一个二分查找需要1g的连续内存,当前系统有2g内存,但是连续内存不足1g,那么就无法使用二分查找。