前言
折半查找是一种基础的查找算法,本文主要介绍了折半查找算法的思路、算法实现,并辅以图示,希望读者可以清晰的理解算法步骤。不足之处欢迎评论区指出。
一、算法思路
算法能够实现查找是基于数组有序这一前提的,对于无序的数组,折半查找并不能起到作用。在有序数组中,通过不断寻找中点元素并与目标元素对比一步步缩小查找区间,最终确定目标元素是否存在于数组之中。
二、算法实现
public static boolean binarySearch(int[] data,int target){
int bottom = 0;
int top = data.length-1;
while(bottom <= top){
int midpoint = (top + bottom)/2;
if (target == data[midpoint]){
return true;
} else if (target < data[midpoint]) {
top = midpoint - 1;
} else {
bottom = midpoint + 1;
}
}
return false;
}
三、算法图示
在数组data上演示折半查找,以元素76
和69
为例。(元素69
并未存在于数组data中)
int[] data = {2,9,11,15,28,33,40,47,51,64,76,77,82,85,94};
通过下面的代码运行折半查找,查找元素76
并打印查找结果。
boolean b = binarySearch(data, 76);
System.out.println(b);
图中黄色区域,表示当前查找区间;红色高亮表示bottom位置,蓝色高亮表示top位置,绿色高亮表示bottom与top重合,向下的黑色箭头表示中点位置。右侧表格中红色箭头、蓝色箭头标识查找区间上界或下界的变化。
通过下面的代码运行折半查找,查找元素69
并打印查找结果。
boolean c = binarySearch(data, 69);
System.out.println(c);
四、算法步骤
1.输入输出
输入
待查找的数组,以及查找目标。
输出
判断查找目标是否存在于待查找数组中,存在返回true
,不存在返回false
。如果需要返回下标等信息,可以自己另做修改。
public static boolean binarySearch(int[] data,int target){}
2.变量初始化
折半查找的“半”怎么查找呢,通过数组的开始元素和最后一个元素的位置来确定。因此需要首先确定botttom:开始位置
和top:结束位置
。初始化时,对于待查找数组,开始位置就是开始元素的下标0
,结束位置就是最后一个元素的下标data.length-1
(数组长度减一)。
int bottom = 0;
int top = data.length-1;
3.查找终止条件
查找有两个出口。一个是循环执行完毕,仍然没有发现目标元素,此时查找终止。另一个是在查找过程中找到了目标元素,提前结束循环,返回结果,查找终止。
while(bottom <= top){
...
return true;
...
}
4.折半的“半”
计算bottom
和top
的均值得到中点的位置。此时注意,除数为整数,得到的结果向下取整,也就是做地板(floor)函数处理。
int midpoint = (top + bottom)/2;
5.缩小查找区间
如果中点位置即是目标元素,则返回结果,查找结束。如果中点位置不是目标元素,基于数组元素有序且从小到大排列这一前提,如果目标元素小于中点元素,则说明应该向左查找,因此将原查找区间缩小至中点元素左半区间。同理,当目标元素大于中点元素时,将原查找区间缩小至中点元素右半区间。值得注意的是,因为在第一步中已经比对了中点元素的值,因此在top = midpoint - 1
和bottom = midpoint + 1
执行的减一和加一操作,是去掉了已经比对过的中点元素,使得查找区间进一步缩小。
if (target == data[midpoint]){
return true;
} else if (target < data[midpoint]) {
top = midpoint - 1;
} else {
bottom = midpoint + 1;
}
总结
算法的思路比较简单,重在对于诸多细节的把握。厘清脉络、注意细节,实现起来就会容易许多。