目录
二分查找
1、何为二分查找
当给我们这样一个数的时候 [1,4,6,7,9];
如果正常一个一个进行查找需要 最好的情况是第一个就是 最坏的情况是最后一个即查找5次
当个数不多的时候,花费时间是可以接受的,但是当个数很大的时候
例如1亿的个数的时候 最坏的情况就是要查找1亿次,花费的时间就无法接受了
因此二分查找就是为了解决这个问题, 这里有个结论即使个数很大 二分查找最多就执行32次
(因为int的取值是-2^31 --- 2^31-1 )
1亿次跟32次比较,显而易见二分查找的效率是非常高效的
二分查找针对的是一个有序的集合。每次都通过跟区间的中间元素对比,将待查找的区间缩小为之前的一半,直到找到要查找的元素,或者区间被缩小为 0。
2、编写二分查找代码
思路:
-
前提:有已经排序好的数组A (这里将的是递增排序)
-
定义左边界L、右边界R,确定搜索范围,循环执行二分查找(3,4步)
-
获取中间索引 m= (L+R)/2 向下取整 ---当然是int直接写就自动向下取整了
-
中间索引的值 A[m] 和待查找的数值T进行比较
① A[m] == T 表示找到,返回中间索引m即可
② A[m] < T ,中间值左侧的其他元素都小于T ,无序比较 ,去中间索引右边去找,m+1 设置为左边界 ,重新查找
③ A[m] > T ,中间值右侧的其他元素都大于T,无序比较, 去中间索引左边去找 m-1 设置为右边界,重新查找
5.当L>R ,表示没有找到,结束循环
package com.sofwin.controller;
/**
* @packageName: com.sofwin.controller
* @author: wentao
* @date: 2022/10/26 9:59
* @version: 1.0
* @email 1660420659@qq.com
* @description: 手写二分查找
*/
public class BinarySearch {
public static void main(String[]args){
int[] array = {1, 4, 5, 23, 31, 43, 47, 54};
int target = 47;
int index = binarySearch(array, target);
System.out.println(index);
}
public static int binarySearch(int[] arr, int tar) {
//左边界L 右边界R 中间值M
int l = 0, r = arr.length-1, m;
while (l <= r) {
//取中间值
m = (l + r) / 2;
if (arr[m] == tar) {
return m;
}else if (arr[m] > tar) {
r = m - 1;
}else {
l = m+1;
}
}
return -1;
}
}
3、问题解决
当L和R都特别大的时候,当L+R相加可能会超过int的取值范围,造成整数溢出,因此我们需要改进一下代码
public class IntegerOverFlow {
public static void main(String[]args){
int l = 0;
int r = Integer.MAX_VALUE;
int m = (l + r) / 2;
//第一不会出现问题
System.out.println(m); //1073741823
// 但是当要查找的是在中间值的右侧的时候
l = m + 1;
//这个时候l+r就超出了int的取值返回 会造成值的溢出
m = (l + r) / 2;
System.out.println(m); //-536870912
}
}
这种情况就会造成溢出问题
方式一:数学问题转换
l = m + 1; //这个时候l+r就超出了int的取值返回 会造成值的溢出 //(l + r) / 2 ==> l / 2 + r / 2 // l - l / 2 + r / 2 ==> l + (r - l) / 2 m = l + (r - l) / 2; System.out.println(m); //1610612735
方式二:无符号右移1位
当数字为正数的时候 无符号右移1位就相当于除以2 (注意负数不成立)
//解决整数溢出的方式2 无符号的右移 并且效率比除法的效率还高 l = m + 1; //这个时候l+r就超出了int的取值返回 会造成值的溢出 //无符号的右移,就是将符号位看着普通的位数 //因为l 和 r都是整数 因此就不会会出现溢出现象了 m = (l + r) >>> 1; System.out.println(m);
4、选择题目1
1.有一个有序表为 1,5,8,11,19,22,31,35,40,45,48,49,50 当二分查找值为48结点的时候,查找成功需要比较的次数
4次
2.使用二分法在序列 1,4,6,7,15,33,39,50,64,78,75,81,89,96 中查找元素81时需要经过几次
4次
上面两题的技巧 奇数就取中间值 偶数就取中间值左面的
3.在拥有128个元素的数组中二分查找一个数,需要比较词素最多不超过多少次
7次
查到1即可 128除以2 整数直接输出 小数取出小数+1
注意:
JDK的Arrays.binarySearch()方法也可以实现二分查找