二分查找前提
进行二分查找的数组是有序数组
二分查找算法思路
- 首先确定该数组的中间下标 mid = (left+right)/2
- 然后让需要查找的数和arr[mid]进行比较
- findVal > arr[mid] 说明你要查找的数在mid的右边,因此需要递归向右进行查找
- findVal < arr[mid] 说明你要查找的数在mid的左边,因此需要递归向左进行查找
- findVal = arr[mid] 说明找到,返回
注意:
使用递归要特别注意结束条件,不然就会成为死递归
- 找到就结束递归
- 遍历完整个数组,仍然没有找到findVal,也需要结束递归 当left>right时就结束了
代码实现
实现返回找到的第一个值的下标
public static void main(String[] args) {
int[] arr = {1, 8, 10, 89, 1000, 1234};
int index = binarySearch(arr, 0, arr.length - 1, 89);
System.out.println("index = "+index);
}
/**
* @param arr 数组
* @param left 左边的下标
* @param right 右边的下标
* @param findVal 查找的值
* @return 返回查找到的第一个下标
*/
private static int binarySearch(int[] arr, int left, int right, int findVal) {
if (findVal < arr[left] || findVal > arr[right] || left > right) { //没有找到
return -1;
}
int mid = (left + right) / 2;
if (findVal < arr[mid]) { //findVal小于中间值 ,则说明在左边,需要左递归
return binarySearch(arr, left, mid - 1, findVal);
} else if (findVal > arr[mid]) { // findVal大于中间值,需要向右递归
return binarySearch(arr, mid + 1, right, findVal);
} else { //相等
return mid;
}
}
返回多个下标
如果数组中待查找的元素有多个,这时就需要返回多个下标.核心思想就是借助于上面查找到的一个下标,向左右两边依次查找,是否还有与findVal相等的值
public class BinarySearch {
public static void main(String[] args) {
int[] arr = {1, 8, 10, 89,1000, 1000, 1000, 1000, 1000, 1234};
List<Integer> indexList = binarySearch2(arr, 0, arr.length - 1, 1000);
System.out.println("indexList = " + indexList);
}
/**
* @param arr 数组
* @param left 左边的下标
* @param right 右边的下标
* @param findVal 待查找的值
* @return 返回查找元素下标的集合
*/
private static List<Integer> binarySearch2(int[] arr, int left, int right, int findVal) {
//递归结束条件
if (findVal < arr[left] || findVal > arr[right] || left > right) {
return new ArrayList<Integer>();
}
List<Integer> indexList = new ArrayList<>();
int mid = (left + right) / 2;
if (findVal < arr[mid]) {
return binarySearch2(arr, left, mid - 1, findVal);
} else if (findVal > arr[mid]) {
return binarySearch2(arr, mid + 1, right, findVal);
} else {
//找到一个下标mid之后,需要像mid的左右两边进行遍历,把值相等的下标,添加到集合中返回
int temp = mid - 1;
//向左边查找
while (true) {
if (temp < 0 || arr[temp] != findVal) {
break;
}
indexList.add(temp);
temp -= 1;
}
//添加mid
indexList.add(mid);
temp = mid + 1;
//向右边查找
while (true) {
if (temp > arr.length - 1 || arr[temp] != findVal) {
break;
}
indexList.add(temp);
temp += 1;
}
return indexList;
}
}