网站首页 > java教程 正文
你有没有过这种体验:在1000个按顺序排好的数字里找“520”,从第一个数开始逐个往后翻,翻到第300个才找到,手都酸了?但用Java二分查找,就像玩“猜数字”游戏,每次都猜中间数,10步之内准能找到!今天用“查字典”“找快递柜”的段子给你讲透,看完就能写代码,再也不用当“人肉遍历机”~
先懂二分查找:像玩“猜数字”,每次都砍半范围,专治“大海捞针”
二分查找的核心逻辑,和你玩过的“猜1-100数字”游戏一模一样:
- 朋友想的数字是“66”,你先猜“50”(中间数),朋友说“小了”;
- 你立马知道数字在“51-100”之间,再猜“75”(新中间数),朋友说“大了”;
- 范围缩到“51-74”,猜“62”,朋友说“小了”;
- 范围缩到“63-74”,猜“68”,朋友说“大了”;
- 再猜“65”(小了),最后猜“66”——5步就中!
要是用“逐个翻”的方法(线性查找),运气差的话得猜66次,而二分查找5次搞定。对应到数组查找:1000个元素,线性查找最多1000步,二分查找只要10步(因为2^10=1024),效率差了100倍!
但二分查找有个“死规矩”:**数组必须是排好序的**,就像猜数字得知道“大了”“小了”的提示,要是数组乱序,连“往哪缩范围”都不知道——就像查字典时,字典页码是乱的,你翻到中间页也没用,纯属瞎猜。
Java二分查找5步走:查字典 analogy 全还原
把二分查找的步骤,套进“查字典找‘Java’这个词”的场景,每一步都超直观,代码也跟着变简单:
1. 初始化边界:确定字典的“首尾页”
第一步是定好查找的“范围”,就像查字典前,先知道字典从第1页(起始索引0)到第1000页(结束索引`数组长度-1`)。
Java代码里,就是给两个变量赋值:
int[] arr = {1,3,5,7,9,11,13}; // 已排序的数组(像排好页的字典)
int target = 7; // 要找的目标值(像“Java”这个词)
int left = 0; // 起始索引(第1页)
int right = arr.length - 1; // 结束索引(最后一页,arr.length=7,所以是6)
2. 计算中间索引:翻到字典“中间页”
第二步是找范围的“中间点”,就像查字典时,直接翻到第500页((1+1000)/2),不用从第1页慢慢翻。
Java里计算中间索引有个小技巧:用`left + (right - left)/2`,别用`(left+right)/2`,避免两个大整数相加溢出(比如left=10亿,right=10亿,相加就超了int范围):
int mid = left + (right - left) / 2; // 计算中间索引,比如left=0,right=6,mid=3
3. 比较中间元素:看“中间页”有没有目标词
第三步是拿“中间页的内容”和“目标”对比,就像翻到字典第500页,看有没有“Java”:
- 要是中间页的词就是“Java”(中间元素=目标值),直接找到,结束查找;
- 要是中间页的词是“C++”(中间元素<目标值),说明“Java”在右边(后面的页数);
- 要是中间页的词是“Python”(中间元素>目标值),说明“Java”在左边(前面的页数)。
Java代码里就是简单的if-else判断:
if (arr[mid] == target) {
System.out.println("找到了,索引是:" + mid); // 中间元素=目标,找到啦
return;
} else if (arr[mid] < target) {
left = mid + 1; // 目标在右边,把起始边界移到中间+1
} else {
right = mid - 1; // 目标在左边,把结束边界移到中间-1
}
4. 调整搜索范围:往左翻或往右翻
第四步是根据对比结果“缩范围”,就像查字典时,发现“中间页是C++,Java在右边”,就把字典起始页改成“501页”,下次只在501-1000页找,范围直接砍半。
比如例子中,arr[mid] = arr[3] = 9,比目标7大,所以把right改成3-1=2,新范围变成left=0,right=2,下次只在{1,3,5}里找——范围从7个元素缩到3个,效率翻倍!
5. 重复查找:直到找到或范围为空
第五步是循环重复2-4步,直到两种情况:
- 找到目标值,输出索引;
- 范围缩到“left > right”(比如字典起始页=501,结束页=500,说明没这页),说明数组里没有目标值。
Java里用while循环实现“重复查找”,完整代码如下:
public static int binarySearch(int[] arr, int target) {
int left = 0;
int right = arr.length - 1;
while (left <= right) { // 范围不为空就继续找
int mid = left + (right - left) / 2;
if (arr[mid] == target) {
return mid; // 找到,返回索引
} else if (arr[mid] < target) {
left = mid + 1; // 往右边找
} else {
right = mid - 1; // 往左边找
}
}
return -1; // 没找到,返回-1
}
// 测试一下
public static void main(String[] args) {
int[] arr = {1,3,5,7,9,11,13};
int target = 7;
int index = binarySearch(arr, target);
System.out.println(index == -1 ? "没找到" : "找到了,索引是:" + index); // 输出“找到了,索引是:3”
}
避坑提醒:这3个坑能让二分查找“翻车”,新手必看!
二分查找看着简单,但新手容易踩坑,用“查字典”类比一下,瞬间明白:
1. **数组没排序就用二分**:就像拿本页码乱的字典查词,翻到中间页看到“Python”,你不知道“Java”在左边还是右边,纯属瞎猜。解决:先用Arrays.sort(arr)给数组排序;
2. **边界处理错(left > right 写成 left < right)**:就像查字典时,起始页=501,结束页=500,还在继续翻,结果越翻越乱。解决:循环条件必须是`left <= right`,确保“最后一页”也能查到;
3. **中间索引计算溢出**:用`(left+right)/2`,当left和right都是10亿时,相加变成20亿,超过int的最大值(约21亿?不,int最大值是2^31-1=2147483647,20亿没超,但15亿+15亿=30亿就超了),结果变成负数,直接翻车。解决:用`left + (right - left)/2`,本质一样,但能避免溢出。
互动时间:来测测你的“二分查找实战力”!
1. 用今天的代码查找数组`[2,4,6,8,10,12]`中的“8”,第一次计算的mid是多少?(提示:left=0,right=5,mid=0+(5-0)/2=2)
2. 要是数组是乱的`[5,3,1,7,9]`,直接用二分查找找“7”,会有啥结果?(提示:数组没排序,会找错或找不到)
3. 你平时找东西(比如找书架上的书、找快递柜里的快递),用过“二分查找”的思路吗?评论区说说你的“高效找物小技巧”!
评论区交出你的答案,前3名答对的送“Java查找算法手册”(含二分查找、插值查找的通俗讲解+代码模板)!关注我,下期揭秘“二分查找的变种——找第一个和最后一个目标值”,解决“数组里有多个重复元素”的难题,实用到爆~
猜你喜欢
- 2025-09-13 面试中如果这样写二分查找_面试分怎么查
- 2025-09-13 图解算法:二分查找树_二分查找法判定树
- 2025-09-13 java中Arrays类中,binarySearch()方法的返回值问题
- 2025-09-13 单片机上实现二分查找+线性插值计算
- 2025-09-13 数据结构之二分查找:c++版本_二分查找算法c语言递归
- 2025-09-13 玩蛇(Python) - 算法:二分查找(Binary Search)
- 2025-09-13 高级Java面试之二分法查找_java二分查找算法代码
- 2025-09-13 秒懂如何运用二分查找算法_二分查找算法是什么意思
- 2025-09-13 【程序员常用十算法】二分查找法—5分钟掌握
- 2025-09-13 看动图学算法(二):二分查找算法的原理和Java讲解
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)