查找分为四种:顺序查找、分块查找、折半查找以及哈希查找。那么二分查找就是折半查找的一种,里面使用了递归。其思想跟我之前写过的快速排序很类似;但是这是这个查找算法,那么我们来写写实现它的思路吧~
首先我们得知道一个点,如果需要用到二分查找的数组一定是一个有序的数组,无序的数组是使用不了的。
满足上面的条件之后,首先找到中点,然后将需要查找的值跟中点值进行比较,其中有三种情况:
①若比中点值大,则在中点右边。
②若比中点值小,则在中点左边。
③若就等于中点值。这里有两种做法,第一种是直接返回数组下标,但是这样是不太好的,为什么?后面实现再来讨论。
经过这一步之后,我们就能知道我们需要查找的值在哪边,那么重复操作不就可以了吗?那么我们就可以使用递归重复使用这个方法直到找到和查找值相同的值,返回数组下标。那么我们来用代码实现以下:
/*
arr为需要查找的数组
left为从左节点中的哪里开始遍历,对递归有用
right为从右节点中的哪里开始结束,也是对递归有用
values是需要查找的值
*/
public static int binarySearch(int arr[], int left, int right, int values){
//定义一个中点值
int middle = (left + right) / 2;
//如果需要查找的值大于中点值,那么向右继续递归遍查找
if(values > arr[middle]){
binarySearch(arr , middle + 1 , right , values);
}else if(values < arr[middle]){//如果需要查找的值小于中点值,那么向左继续递归查找
binarySearch(arr , left , middle - 1 , values);
}else { //如果需要查找的值等于中点值,则返回数组下标
return middle;
}
}
思考一下,这里会有什么问题呢?那我们要知道我们有时候查找数值不止一个,这样以上面的代码去实现的话,只会返回第一个就会结束程序,那么剩余的怎么办?所以当数组中有重复数据,那么就不能这样写,我们得修改一下当values等于中点值的时候里面的代码。怎么修改?
我们需要知道,找到了中点值,可能前面还有呢?可能后面还有呢?那么我们就向前和向后遍历去寻找有没有相同的,有的话加入一个ArrayList里。代码修改如下:
//相同的代码我就不做注释了
public static ArrayList<Integer> binarySearch(int arr[] , int left , int right , int values){
int middle = (left + right) / 2;
if(values > arr[middle]){
binarySearch(arr , middle + 1 , right , values);
}else if(values < arr[middle]){
binarySearch(arr , left , middle - 1, values);
}else{
//新建一个ArrayList去存储
ArrayList<Integer> list = new ArrayList<>();
//向前遍历,我们从哪里开始呢?当然是middle - 1啦,定义一个temp结束循环变量
int temp = middle - 1;
while(true){
//设置退出循环的条件,否则是个死循环
if(temp < 0 || arr[temp] != values){
break;
}
list.add(temp);
temp -= 1;
}
//当然还得把中间的加入list
list.add(middle);
//重新设置temp值进行向后遍历
temp = middle + 1;
while(true){
if(temp > right || arr[temp] != values){
break;
}
list.add(temp);
temp += 1;
}
}
return list;
}