/**
* 理论回顾:
* (1)二进制数中位:表示N个连续整数需要多少位?
* 一个16位的short整形表示65536个范围-32768到32767的整数。B个位表示2^B个不同整数。
* 故表示N个连续整数需要位数B满足2^B>=N,故B>=logN,最小位数是[logN](上取整)
* (2)重复翻倍:从X=1开始,在X至少和N一样大之前应该翻倍多少次?
* 1,2,4,8,,,为2^k故2^k>=N.故k=[logN](上取整)
* (3)重复减半:从X=N开始,如果N被重复减半,要使N<=1需要做多少次迭代?
* 如果除法向上舍入迭代[logN](上取整)次
* 如果除法向下舍入迭代[logN](下取整)次,用X=3模拟即可理解
*/
public class BinarySearch {
/**
* @author limingyu
* 二分搜索:从数组的中间开始执行。如果low比high大,则这个项不会存在,返回-1。否则,设mid为范围的中点
* (如果这个范围有偶数个元素就向下舍入),将待查找的项k与位于mid的项比较,找到匹配的返回。
* 二分搜索应用了重复减半原理,迭代次数为O(logN)
*/
public static void main(String[] args) {
int[] arr = new int[]{7,14,18,21,23,29,31,35,38,42,46,49,52};
// int index = binarySearch(arr, 22);
// System.out.println(index);
int index = binarySearch1(arr,35);
System.out.println(index);
}
/**
* 对一个不成功的查找,循环中迭代的次数为[logN]+1(下取整),原因:在每次迭代中将范围减半(如果范围内有偶数个元素就向下舍入)
* 加一是因为最后的范围包含o个元素。
* 对于一个成功的查找,最坏的情况是[logN](下取整)次迭代,原因:在最坏情况下最终到达了只有一个元素的范围。
* 平均情况只少了一次迭代因为:一半的元素需要最坏的情况下查找,四分之一的元素节省了一次迭代,2^i个元素中只有一个会在最坏情况中节省i次迭代。
* 对于一次成功的查找,平均需要[logN]-1(下取整)次迭代,每次迭代平均使用1.5次比较。
*/
public static int binarySearch(int a[],int k){
int low = 0;
int high = a.length-1;
int mid = 0;
while(low <= high){//只有在low>high时才可能查找失败
mid = (low + high) / 2;
if(a[mid] < k){
low = mid + 1;
}else if(a[mid] > k){
high = mid - 1;
}else{
return mid;
}
}
return -1;
}
/**
* 优化的二分搜索将比较次数减少约一半
* 如果待查找的项小于等于mid位置的项,那么他在包含mid位置的范围内。
* 当跳出循环时,子范围是1,测试是否匹配成功,若不成功就返回-1。
* 此时迭代次数为[logN](下取整),比较次数为[logN]+1。
*/
public static int binarySearch1(int a[],int k){
int low = 0;
int high = a.length-1;
int mid = 0;
while(low < high){
mid = (low + high) / 2;
if(a[mid] < k){
low = mid + 1;
}else{
high = mid;
}
}
if(a[low] == k){//low等于high代表匹配成功的最坏情况或者将匹配失败
return high;//此时low等于high
}
return -1;
}
}
二分查找过程