最普通的写法:

static int bs1(int[] arr,int key){
int L = 0,R = arr.length - 1; //在[L,R]范围内寻找key
int mid;
while( L <= R){
mid = L + (R - L) / 2;
if(arr[mid] == key)
return mid;
if(arr[mid] > key)
R = mid - 1;// key 在 [L,mid-1]内
else
L = mid + 1;
}
return -1;
}
首先说明,这个和上面的二分查找是完全一样的,只不过我们定义的区间不同而已:
//和上面的完全一样,只是一开始R不是arr.length-1 而是arr.length
static int bs2(int[] arr,int key){
int L = 0, R = arr.length; //注意这里R = arr.length 所以在[L,R)开区间中找
int mid;
while( L < R){ //注意这里 不是 L <= R
mid = L + (R - L)/2;
if(arr[mid] == key)
return mid;
if(arr[mid] > key)
R = mid; // 在[L,mid)中找
else
L = mid + 1;
}
return -1;
}
上面的两种方式一般还是第一种方式用的多一点。
这个和之前的不同是:
举个例子:

/**查找第一个与key相等的元素的下标, 如果不存在返回-1 */
static int firstEqual(int[] arr,int key){
int L = 0, R = arr.length - 1; //在[L,R]查找第一个>=key的
int mid;
while( L <= R){
mid = L + (R - L)/2;
if(arr[mid] >= key)
R = mid - 1;
else
L = mid + 1;
}
if(L < arr.length && arr[L] == key)
return L;
return -1;
}
这个和上面那个寻找第一个等于key的唯一的区别就是:
/**查找第一个大于等于key的元素的下标*/
static int firstLargeEqual(int[] arr,int key){
int L = 0, R = arr.length - 1;
int mid;
while( L <= R){
mid = L + (R - L) / 2;
if(arr[mid] >= key)
R = mid - 1;
else
L = mid + 1;
}
return L;
}
这个和上两个的不同在于:
举个例子:

/**查找第一个大于key的元素的下标 */
static int firstLarge(int[] arr,int key){
int L = 0,R = arr.length - 1;
int mid;
while(L <= R){
mid = L + (R - L) / 2;
if(arr[mid] > key)
R = mid - 1;
else
L = mid + 1;
}
return L;
}
上面写了三个第一个.....的程序,可以发现一些共同点 ,也可以总结一下它们微妙的区别:
和寻找第一个 = key的很类似,不过是方向的不同而已:
举个例子:

/**查找最后一个与key相等的元素的下标, 如果没有返回-1*/
static int lastEqual(int[] arr,int key){
int L = 0, R = arr.length - 1;
int mid;
while( L <= R){
mid = L + (R - L)/2;
if(arr[mid] <= key)
L = mid + 1;
else
R = mid - 1;
}
if(R >= 0 && arr[R] == key)
return R;
return -1;
}
这个和上面那个寻找最后一个等于key的唯一的区别就是:
/**查找最后一个小于等于key的元素的下标 */
static int lastSmallEqual(int[] arr,int key){
int L = 0, R = arr.length - 1;
int mid;
while( L <= R){
mid = L + (R - L) / 2;
if(arr[mid] <= key)
L = mid + 1;
else
R = mid - 1;
}
return R;
}
这个和上面两个不同的是:

/**查找最后一个小于key的元素的下标*/
static int lastSmall(int[] arr,int key){
int L = 0, R = arr.length - 1;
int mid;
while(L <= R){
mid = L + (R - L) / 2;
if(arr[mid] < key)
L = mid + 1;
else
R = mid - 1;
}
return R;
}
上面三个都是求最后一个.....的,也进行一下总结:
public class BinarySearch {
//最普通的二分搜索法
static int bs1(int[] arr,int key){
int L = 0,R = arr.length - 1; //在[L,R]范围内寻找key
int mid;
while( L <= R){
mid = L + (R - L) / 2;
if(arr[mid] == key)
return mid;
if(arr[mid] > key)
R = mid - 1;// key 在 [L,mid-1]内
else
L = mid + 1;
}
return -1;
}
//和上面的完全一样,只是一开始R不是arr.length-1 而是arr.length
static int bs2(int[] arr,int key){
int L = 0, R = arr.length; //注意这里R = arr.length 所以在[L,R)开区间中找
int mid;
while( L < R){ //注意这里 不是 L <= R
mid = L + (R - L)/2;
if(arr[mid] == key)
return mid;
if(arr[mid] > key)
R = mid; // 在[L,mid)中找
else
L = mid + 1;
}
return -1;
}
/**查找第一个与key相等的元素的下标, 如果不存在返回-1 */
static int firstEqual(int[] arr,int key){
int L = 0, R = arr.length - 1; //在[L,R]查找第一个>=key的
int mid;
while( L <= R){
mid = L + (R - L)/2;
if(arr[mid] >= key)
R = mid - 1;
else
L = mid + 1;
}
if(L < arr.length && arr[L] == key)
return L;
return -1;
}
/**查找第一个大于等于key的元素的下标*/
static int firstLargeEqual(int[] arr,int key){
int L = 0, R = arr.length - 1;
int mid;
while( L <= R){
mid = L + (R - L) / 2;
if(arr[mid] >= key)
R = mid - 1;
else
L = mid + 1;
}
return L;
}
/**查找第一个大于key的元素的下标 */
static int firstLarge(int[] arr,int key){
int L = 0,R = arr.length - 1;
int mid;
while(L <= R){
mid = L + (R - L) / 2;
if(arr[mid] > key)
R = mid - 1;
else
L = mid + 1;
}
return L;
}
/**查找最后一个与key相等的元素的下标, 如果没有返回-1*/
static int lastEqual(int[] arr,int key){
int L = 0, R = arr.length - 1;
int mid;
while( L <= R){
mid = L + (R - L)/2;
if(arr[mid] <= key)
L = mid + 1;
else
R = mid - 1;
}
if(R >= 0 && arr[R] == key)
return R;
return -1;
}
/**查找最后一个小于等于key的元素的下标 */
static int lastSmallEqual(int[] arr,int key){
int L = 0, R = arr.length - 1;
int mid;
while( L <= R){
mid = L + (R - L) / 2;
if(arr[mid] <= key)
L = mid + 1;
else
R = mid - 1;
}
return R;
}
/**查找最后一个小于key的元素的下标*/
static int lastSmall(int[] arr,int key){
int L = 0, R = arr.length - 1;
int mid;
while(L <= R){
mid = L + (R - L) / 2;
if(arr[mid] < key)
L = mid + 1;
else
R = mid - 1;
}
return R;
}
public static void main(String[] args) {
int[] arr = {1,3,4,6,6,6,6,6,6,8,9};
System.out.println("----------general-----------");
System.out.println(bs1(arr,3));//1
System.out.println(bs2(arr,3));//1
System.out.println(bs2(arr,6));//5
System.out.println("-----------first------------");
//第一个 = 的
System.out.println(firstEqual(arr,6));//3
//第一个 >= 的
System.out.println(firstLargeEqual(arr,5));//3
System.out.println(firstLargeEqual(arr,6));//3
//第一个 > 的
System.out.println(firstLarge(arr,6));//9
System.out.println("------------last------------");
//最后一个 = 的
System.out.println(lastEqual(arr,6));//8
// 最后一个 <= 的
System.out.println(lastSmallEqual(arr,7));//8
System.out.println(lastSmallEqual(arr,6));//8
//最后一个 < 的
System.out.println(lastSmall(arr,6));//2
}
}
效果:


