二分查找的思想
二分查找,在一个数组有序(比如从小到大)的情况下,如果想查找某个数值是否存在于数组中,这个时候就可以使用二分查找了。具体做法就是找出数组的中间下标的元素,然后拿查找值与其比较,如果查找值小于中间元素值,则缩小查找范围在小于中间元素的范围查找;否则,在大于中间元素值得范围查找。一直到找到查找值,或者区间缩小为0.
图解:
代码
可以使用循环来实现,也可以使用递归。
package com.study.algorithm.search;
/**
* @Auther: JeffSheng
* @Date: 2019/8/27 15:57
* @Description:
* 二分查找
*/
public class BinarySearch {
public static int bsearch(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (a[mid] == value) {
return mid;
} else if (a[mid] < value) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
/**
* 二分查找的递归实现
* @param a
* @param n
* @param val
* @return
*/
public static int bsearchRecursion(int[] a, int n, int val) {
return bsearchInternally(a, 0, n - 1, val);
}
private static int bsearchInternally(int[] a, int low, int high, int value) {
if (low > high){
return -1;
}
int mid = low + ((high - low) >> 1);
if (a[mid] == value) {
return mid;
} else if (a[mid] < value) {
return bsearchInternally(a, mid+1, high, value);
} else {
return bsearchInternally(a, low, mid-1, value);
}
}
public static void main(String[] args) {
int[] a={0,1,20,31,45,52,60,72,89,96};
//循环实现
System.out.println(bsearch(a,10,52));
//递归实现
System.out.println(bsearchRecursion(a,10,52));
}
}
二分查找的时间复杂度分析
二分查找,每次查找数据范围缩小为原来一半,假如数组元素个数为n,那么 第一次在n个数据见查找,第二次为n/2,第三次n/4,一直到范围缩小为空。n,n/2,n/4......n/2^k,k就是数据范围缩小的次数,经过k次缩小找到了数据则n/2^k=1,则k就等于logn,而每次这是比较中间值和查找值,所以二分查找的时间复杂度为O(logn).
O(logn)的时间复杂度是非常高效的,即便2^32个数,貌似是21亿个数,对log2^32来说也不过是32次比较,所以说O(logn)的时间复杂度甚至有时比O(1)的还要高效。因为有的O(1)的常量是10000或者还要大的有限次。
二分查找的应用场景
二分查找依赖于顺序表结构。
二分查找适合有序数据,若数据无序则需要先排序。但是数据本身需要是静态的,只需要一次排序这种就很合适,可以做到均摊时间复杂度;但如果数据本身是动态插入或者删除的则需要多次排序的时间复杂度就很高。
二分查找不适合数据量小得的,数据量太小直接遍历就行了。
二分查找也不适合数据量太大的,数据量太大因为是数组可能无法利用内存空间。
应用:二分法查找一个正整数的平方根,要去精确到小数点后6位
package com.study.algorithm.search;
/**
* @Auther: JeffSheng
* @Date: 2019/8/27 16:54
* @Description:
* 二分法:求一个数的平方根,要求精确到小数点后6位
*/
public class SquareRoot {
public static double getSquareRoot(int num){
double low=1,high=num;
double mid = (low + high) / 2;
while(low<=high){
mid = (low + high) / 2;
if(mid*mid ==num){
return mid;
}else if(mid*mid < num){
low = mid+0.000001 ;
}else{
high = mid-0.000001;
}
}
return mid;
}
public static void main(String[] args) {
double x = getSquareRoot(10);
System.out.println(x+"----------"+x*x);
System.out.println(Math.sqrt(10));
}
}