1. 程式人生 > >二分查詢及其擴充套件

二分查詢及其擴充套件

#二分查詢及其擴充套件#

  • 二分查詢法
    • 時間複雜度
      • O(logn)
    • 實現
      • 遞迴
public int binarySearchV2(int[] a,int low,int high,int value) {

        if(low>high) return -1;

        while (low<=high){
            int mid = (low+high)/2;
            if(a[mid]  == value){
                return mid;
            }else if(a[mid] > value){
               return binarySearchV2(a,low,high-1,value);
            }else {
               return binarySearchV2(a,mid+1,high,value);
            }
        }
			return -1;
    }
	- **非遞迴**
public int binarySearchV1(int[] a,int n,int value){
       int low = 0;
       int high = n-1;
       while(low<=high){
           int mid = (low+high)/2;
           if(a[mid] == value){
               return mid;
           }else if(a[mid]>value){
               high = mid - 1;
           }else{
               low = mid+1;
           }
       }
       return -1;
    }
  • 注意點
    • 退出迴圈的條件是low <= high
    • (low+high)容易溢位 改為 low+(high-low)/2 ==> >>1
    • low 和 high的更新
  • 擴充套件
    • 順序訪問及查詢
    • 基於陣列
    • 資料量太大不適合,資料量太小也不適合
  • 相關變形題目
    • 查詢第一個值等於給定值的元素
    • 查詢最後一個值等於給定值的元素
    • 查詢第一個大於等於給定值的元素
    • 查詢最後一個小於等於給定值的元素
  • 分析
    • 以上幾個都是二分查詢的變形題目,需要學會舉一反三,相信大部分人一看程式碼馬上就能懂了
	/**
     * 獲取第一個等於給定值的值
     * */
    public static int getFisrtEquals(int[] a,int n,int value){
        int low = 0;
        int high = n-1;

        while(low <= high){
            int mid = low + ((high-low)>>1);
            if(a[mid] >value){
                high = mid-1;
            }else if(a[mid] <value){
                low = mid+1;
            }else {
                // 如果mid已經到陣列第一位肯定是第一個等於value 或者mid=value且前一位不等於value
                if(mid ==0 || a[mid-1] != value) return mid;
                // 否則高位等於mid-1,相當於往前移一位
                else high = mid-1;

            }
        }
        return -1;
    }

    /**
     * 獲取最後一個等於給定值的
     */
    public static int getLastEquals(int[] a,int n,int value){
        int low = 0;
        int high = n-1;
        while(low <= high){
            int mid = low + ((high-low)>>1);

            if(a[mid] >value){
                high = mid -1;
            }else if(a[mid]<value){
                low = mid+1;
            }else{
                if(mid == n-1 || a[mid+1]!=value) return mid;
                else low = mid+1;
            }
        }
        return -1;
    }

    /**
     * 獲取第一個大於等於給定值的
     */
    public static int getFirstMoreThanEquals(int[] a,int n,int value){
        int low = 0;
        int high = n-1;
        while(low <= high){
            int mid = low + ((high-low)>>1);

            if(a[mid]<value){
                low = mid+1;
            }else{
                if(mid==0 || a[mid-1]<value){
                    return mid;
                }else {
                    high = mid - 1;
                }
            }
        }
        return -1;
    }
    /**
     * 最後一個小於等於給定值的
     */
    public static int getLastSmallerEquals(int[] a,int n ,int value){
        int low = 0;
        int high = n-1;
        while(low <= high){
            int mid = low + ((high-low)>>1);

            if(a[mid]>value){
                high = mid-1;
            }else{
				// 應該就比較好理解了
                if(mid==n || a[mid+1]>value) return mid;
                else low=mid+1;


            }
        }
        return -1;
    }
  • 想要寫出一個 bug free的二分查詢也不容易,需要考慮 迴圈的終止條件,區間的上下界值的選擇以及返回值的選擇