思路
二分法查找的目标数组必须为有序数组,以一个从小到大排列的数组为例:
- 首先确定该数组的中间下标mid = (left + right) / 2
- 然后用查找目标数targetVal和arr[mid]比较
- targetVal > arr[mid],查找的目标数在mid右边
- targetval < arr[mid],查找的目标数在mid左边
- targetVal = arr[mid],找到目标数
代码
示例包括使用递归二分法和wile循环二分法,支持查找多个目标数
package com.leolee.dataStructure.search;
import java.util.HashSet;
import java.util.Set;
/**
* @ClassName BinarySearch
* @Description: 二分法查找(查找的数组为有序的)
* 思路,以一个从小到大的数组为例:
* 1.首先确定确定该数组的中间下标mid=(left+right)/2
* 2.然后用目标数targetVal与arr[mid]比较
* 2.1targetVal > arr[mid] 查找的目标数在mid的右边
* 2.2target = arr[mid] 查找的目标数找到
* 2.2targetVal < arr[mid] 查找的目标数在mid的左边
* 什么时候结束递归:
* 1)找到就结束递归
* 2)递归查询了整个数组,仍找不到目标数,当left > right退出
* @Author LeoLee
* @Date 2020/11/1
* @Version V1.0
**/
public class BinarySearch {
/*
* 功能描述: <br>
* 〈二分查找〉查找目标数组只存在一个目标数,递归方式
* @Param: [arr 查找目标数组, left, right, targetval 目标数]
* @Return: int 目标数的下标,不存在返回-1
* @Author: LeoLee
* @Date: 2020/11/1 14:45
*/
public static int search(int[] arr, int left, int right, int targetval) {
int mid = (left + right) / 2;
int midVal = arr[mid];
if (left > right) {
return -1;
}
if (targetval > midVal) {//向右递归
return search(arr, mid + 1, right, targetval);
} else if (targetval < midVal) {//向左递归
return search(arr, left, mid - 1, targetval);
} else if (targetval == midVal) {
return mid;
}
return -1;
}
/*
* 功能描述: <br>
* 〈二分查找〉查找目标数组只存在一个目标数, while方式
* @Param: [arr 查找目标数组, left, right, targetval 目标数]
* @Return: int 目标数的下标,不存在返回-1
* @Author: LeoLee
* @Date: 2020/11/1 14:45
*/
public static int search(int[] arr, int targetval) {
int left = 0;
int right = arr.length - 1;
int mid = 0;
while (!(left > right)) {
mid = (left + right) / 2;
if (targetval > arr[mid]) {
left = mid + 1;
} else if (targetval < arr[mid]) {
right = mid -1;
} else {
return mid;
}
}
return -1;
}
/*
* 功能描述: <br>
* 〈二分查找〉支持目标数组存在多个目标数
* 在找到目标数之后不要马上返回
* @Param: [arr 查找目标数组, left, right, targetval 目标数]
* @Return: int 目标数的下标,不存在返回-1
* @Author: LeoLee
* @Date: 2020/11/1 15:00
*/
public static Set search2(int[] arr, int targetval) {
int left = 0;
int right = arr.length - 1;
int mid = 0;
Set set = new HashSet();
while (!(left > right)) {
mid = (left + right) / 2;
if (targetval > arr[mid]) {
left = mid + 1;
} else if (targetval < arr[mid]) {
right = mid -1;
} else {
//在找到目标数之后不要马上返回
//分别向mid左右两边扫描,将所有与arr[mid]相同的数全部找出来放入集合
int temp = mid - 1;
while (true) {
//退出条件
if (temp < 0 || arr[temp] != targetval) {
break;
}
set.add(temp);
temp-=1;
}
temp = mid + 1;
while (true) {
//退出条件
if (temp > arr.length -1 || arr[temp] != targetval) {
break;
}
set.add(temp);
temp+=1;
}
set.add(mid);
break;
}
}
return set;
}
public static void main(String[] args) {
int[] arr = {1, 8, 10, 89, 1000, 1234};
System.out.println(BinarySearch.search(arr, 0, arr.length - 1, 8));
System.out.println(BinarySearch.search(arr, 8));
int[] arr2 = {1, 8, 10, 89, 1000, 1000, 1234};
BinarySearch.search2(arr2, 1000).forEach(e -> {
System.out.print(e + ",");
});
}
}