最普通的写法:
- 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
-
- }
- }
-
-
效果: