目录
1、什么是二分查找
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列
2、编写二分查找代码
(1)前提:有已排序数组A(假设已经做好)
(2)定义左边界L、右边界R,确定搜索范围,循环执行二分查找(3、4步骤)
(3)获取中间索引M = Floor((L+R)/2)
(4)中间索引的值A[M]与待搜索的值T进行比较
① A[M] == T 表示找到,返回中间索引
② A[M] > T,中间值右侧的其他元素都大于T,无需比较,中间索引左边去找,M - 1设置为右边界,重新查找
③ A[M] < T,中间值左侧的其他元素都小于T,无需比较,中间索引右边去找,M + 1设置为左边界,重新查找
(5)当L>R时,表示没有找到,应结束循环
public class BinarySearch {
public static void main(String[] args){
int[] arr = {1, 2, 5, 8, 11, 17, 22, 31, 35, 40, 45, 48, 49, 50};
int target = 48;
int idx = binarySearch(arr, target);
System.out.println(idx);
}
public static int binarySearch(int[] a, int t) {
int l = 0, r = a.length - 1, m;
while (l <= r) {
m = (l + r) / 2;
if (a[m] == t) {
return m;
}else if (a[m] >t){
r = m - 1;
}else {
l = m + 1;
}
}
return -1;
}
}
3、解决整数溢出
为什么会产生整数溢出呢?如下m =(l + r) 超出整数存储最大值
int l = 0;
int r = Integer.MAX_VALUE - 1;
int m = (l + r) / 2;
System.out.println(m); //打印结果为:1073741823
//如果查找到数据在右侧范围内
l = m + 1 ;
m = (l + r) / 2; //l+r 超出整数存储最大值
System.out.println(m); //打印结果为:-536870913
(1)方法一:公式转换
int l = 0;
int r = Integer.MAX_VALUE - 1;
int m = l + (r - l) / 2; // (l + r) / 2 ==> l/2 + r/2 ==> l + (-l/2 + r/2) ==> l + (r-l)/2
System.out.println(m); //打印结果为:1073741823
//如果查找到数据在右侧范围内
l = m + 1 ;
m = l + (r - l) / 2;
System.out.println(m); //打印结果为:1610612735
(2)方法二:无符号右移运算代替除法
int l = 0;
int r = Integer.MAX_VALUE - 1;
int m = (r + l) >>> 1; //无符号右移
System.out.println(m); //打印结果为:1073741823
//如果查找到数据在右侧范围内
l = m + 1 ;
m = (r + l) >>> 1;
System.out.println(m); //打印结果为:1610612735
4、相关练习
1.有一个有序表为1,5,8,11,19,22,31,40,45,48,49,50 当二分查找值为48的节点时,查找成功需要比较的次数
答:4次
2.使用二分法在序列1,4,6,7,15,32,39,50,64,78,79,81,88,89 中查找元素为81的节点时,需要经过几次比较
答:4次
3.在拥有128个元素的数组中二分查找一个数,需要比较的次数最多不超过多少次
答:7次
5、总结
● 奇数二分取中间
● 偶数二分取中间靠左
● 2ⁿ = 128 或 128 /2/2...直到等于1
●问题转换为,如果有计算机,用 /
计算出是整数,则该整数即为最终结果
计算出是小数,则舍去小数部门,整数加一为最终结果
6、注意事项
(1)目前介绍的二分查找是以jdk中Arrays.binarySearch的实现作为讲解示范,后续选择题的解答思路也是以此为准
(2)但实际上,二分查找有诸多辩题,一旦使用变体的实现代码,则左右边界的选取会有变化,进而会影响之前选择题的答案选择