二分查找法介绍
二分查找又叫折半查找,要求待查找的序列有序
。每次取中间位置的值与待查关键字比较,如果中间位置的值比待查关键字大,则在前半部分循环这个查找的过程,如果中间位置的值比待查关键字小,则在后半部分循环这个查找的过程。直到查找到了为止,否则序列中没有待查的关键字。
二分查找的思路分析
- 首先确定该数组的中间的下标
mid = (left + right) / 2
- 然后让需要查找的数
findVal 和 arr[mid] 比较
若findVal > arr[mid]
, 则要找的数在mid 的右边, 因此需要递归的向右查找。
若findVal < arr[mid]
, 则要找的数在mid 的左边, 因此需要递归的向左查找
若findVal == arr[mid]
说明找到,就返回。 - 什么时候我们需要结束递归?
第一种情况: 找到我们要找的值就结束递归 。
第二种情况递归完整个数组,仍然没有找到findVal ,也需要结束递归 当 left > right 就需要退出。
示例:对一个有序数组进行二分查找 {1,8, 10, 89, 1000, 1234}
代码演示:
public class BinarySearch {
public static void main(String[] args) {
int arr[]={1,8, 10, 89, 1000, 1234};
int left=arr[0];
int right=arr[arr.length-1];
int resindex=binarySearch( arr,0,arr.length-1,1000);
System.out.println("要找的值对应的索引为"+resindex);
}
//left为左边的索引,right为右边索引
public static int binarySearch(int[] arr, int left, int right, int findVal) {
int mid = (left + right) / 2;
//当left>right,说明递归了整个数组没找到对应得值
if (left > right) {
return -1;
}
if (findVal > arr[mid]) {
return binarySearch(arr, mid + 1, right, findVal);
} else if (findVal < arr[mid]) {
return binarySearch(arr, left, mid - 1, findVal);
} else {
return mid;
}
}
}
代码改进:
上面的代码当在数组中找到对应的值时就返回,只针对要找的值只有一个的情况,当要找的值在数组中有多个时,我们应该把它对应的多个索引值加入到一个集合中去并返回这个集合,改进后的代码如下:
public class BinarySearch {
public static void main(String[] args) {
int arr[]={1,8, 10, 89, 1000, 1234};
int left=arr[0];
int right=arr[arr.length-1];
List<Integer> resIndexList=binarySearch( arr,0,arr.length-1,1000);
System.out.println("要找的值对应的索引为"+resIndexList);
}
public static List<Integer> binarySearch(int[] arr, int left, int right, int findVal) {
int mid = (left + right) / 2;
if (left > right) {
return new ArrayList<Integer>();
}
if (findVal > arr[mid]) {
return binarySearch(arr, mid + 1, right, findVal);
} else if (findVal < arr[mid]) {
return binarySearch(arr, left, mid - 1, findVal);
} else {
List<Integer> resIndexList=new ArrayList<Integer>();
//向mid索引值的左边扫描,将所有找到的对应值的下标加入到集合中
int temp=mid-1;
while(true){
if(temp<0||arr[temp]!=findVal){
break;
}
resIndexList.add(temp);
temp -=1;//temp左移
}
resIndexList.add(mid);
//向mid索引值的右边扫描,将所有找到的对应值的下标加入到集合中
temp=mid+1;
while(true){
if(temp>arr.length-1||arr[temp]!=findVal){
break;
}
resIndexList.add(temp);
temp +=1;//temp右移
}
return resIndexList;
}
}
}