专业的JAVA编程教程与资源

网站首页 > java教程 正文

找1个数要翻遍整个数组?二分查找“猜数字”式搜素,只要10步!

temp10 2025-09-13 09:12:14 java教程 3 ℃ 0 评论

你有没有过这种体验:在1000个按顺序排好的数字里找“520”,从第一个数开始逐个往后翻,翻到第300个才找到,手都酸了?但用Java二分查找,就像玩“猜数字”游戏,每次都猜中间数,10步之内准能找到!今天用“查字典”“找快递柜”的段子给你讲透,看完就能写代码,再也不用当“人肉遍历机”~

先懂二分查找:像玩“猜数字”,每次都砍半范围,专治“大海捞针”

找1个数要翻遍整个数组?二分查找“猜数字”式搜素,只要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查找算法手册”(含二分查找、插值查找的通俗讲解+代码模板)!关注我,下期揭秘“二分查找的变种——找第一个和最后一个目标值”,解决“数组里有多个重复元素”的难题,实用到爆~

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表