二分查找的思路
1、将待查找的数组arr[]进行排序,这里进行二分查找的数组规定是有序的。接下来的讨论是基于升序的数组进行的。
2、确定待查找数组的中见下标 mid = (left + right) / 2;让中间值与待查找的目标值findVal进行比较。
3、分为以下几种情况:当findVal > arr[mid]时,则向右进行递归二分查找;
当findVal < arr[mid]时,则向左进行递归二分查找;
当findVal == arr[mid]时,则返回mid。
4、结束递归:当找到待查找值的下标就结束递归;或者虽然没找到findVal,但是当left > right时也得结束递归。
二分查找的代码实现
以下代码是针对所查找的数在数组中无重复的情况:
/**
*
* @param arr 要查找的数组
* @param left 左边的索引
* @param right 右边的索引
* @param findlVal 要查找的值
* @return 如果找到返回下标,没有找到返回-1
*/
public static int binarySearch(int[] arr,int left,int right,int findlVal) {
if (left > right) {
return -1;
}
int mid = (left + right) / 2;
int midVal = arr[mid];
if (findlVal > midVal) {//向右递归
return binarySearch(arr, mid + 1, right, findlVal);
} else if (findlVal < midVal) {//向左递归
return binarySearch(arr, left, mid - 1, findlVal);
} else {
return mid;
}
}
以下是针对所查找的值在数组中有重复的情况,具体思路是,当findVal == arr[mid]时,需要从mid的左右两边分别扫描,将所有查找到的索引装入到一个动态数组中。
public static List<Integer> binarySearch2(int[] arr, int left, int right, int findlVal) {
if (left > right) {
return new ArrayList<Integer>();//返回一个空的数组
}
int mid = (left + right) / 2;
int midVal = arr[mid];
if (findlVal > midVal) {//向右递归
return binarySearch2(arr, mid + 1, right, findlVal);
} else if (findlVal < midVal) {//向左递归
return binarySearch2(arr, left, mid - 1, findlVal);
} else {//fingVal == midVal 这里就需要进行左右两边扫描
//new一个动态数组用来存放索引
List<Integer> resIndexlist = new ArrayList<Integer>();
//向mid的左边进行扫描
int temp = mid - 1;
while(true){
if (temp < 0 || arr[temp] != findlVal){//当越过左边界或者两数不相等时,退出循环
break;
}
resIndexlist.add(temp);
temp -= 1;//继续向左扫描
}
//不要忘了把中间的索引加进去,因为向左向右扫描是基于findVal == arr[mid]
resIndexlist.add(mid);
//向右扫描
temp = mid + 1;
while(true){
if (temp > arr.length -1 || arr[temp] != findlVal){//当越过右边界或者两数不相等时,退出循环
break;
}
resIndexlist.add(temp);
temp += 1;//继续向右扫描
}
return resIndexlist;
}
}