【问题标题】:modify binary search to find the next bigger item than the key修改二分查找以找到下一个比键更大的项
【发布时间】:2013-04-19 15:46:38
【问题描述】:

我想修改著名的binary search 算法以返回下一个更大项的索引,而不是正在搜索的键。

所以我们有4个案例:

  1. key小于所有item,返回0。
  2. key 大于所有项,返回 items.length。
  3. 在索引 x 处找到键,返回 x+1。
  4. 未找到键,返回下一个更大的索引。

例如:

data = { 1, 3, 5, 7, 9, 11 };
  • 搜索 0 返回 0。
  • 搜索 11 或 12 返回 6。
  • 搜索 5 或 6 返回 3。

    while (low <= high) {
        mid = (low + high) / 2;
        if (data[mid] < val)
            low = mid + 1;
        else if (data[mid] > val)
            high = mid - 1;
        else {
            break;
        }
    }
    

目前通过检查低值和高值使其工作。 有没有什么有趣的代码可以这样做!

编辑!!!

这是我的工作方式:

    if (low <= high)
        found = (low + high) / 2 + 1;
    else if (low >= data.length)
        found = data.length ;
    else if (high < 0)
        found = -1;
    else
        found = low;

我正在寻找更优雅的方式!

编辑二!!!

如果没有重复,此代码有效。 为了处理重复的情况,我们需要修改第一个 if 条件:

if (low <= high)
    found = (low + high) / 2 + 1;

迭代直到找到更大的元素。

【问题讨论】:

  • 你正在实现std::upper_bound的算法。
  • "搜索 4 或 5 返回 3" 错误!搜索 4 应该返回 2,搜索 5 返回 3。
  • @ElKamina 更正搜索 5 或 6 返回 3!

标签: algorithm binary-search


【解决方案1】:
  1. 列表项

这是一个代码:

  • 返回要搜索的元素的索引 如果元素存在
  • 如果数组中不存在搜索的元素,则返回下一个更大元素的索引
  • 如果搜索到的元素大于数组的最大元素,则返回 -1
      public static int ceilSearch(int arr[], int low, int high, int x) {
    int mid;
    if (x <= arr[low])
      return low;
    if (x > arr[high])
      return -1;

    mid = (low + high) / 2; /* low + (high - low)/2 */

    if (arr[mid] == x)
      return mid;

    else if (arr[mid] < x) {
      if (mid + 1 <= high && x <= arr[mid + 1])
        return mid + 1;
      else
        return ceilSearch(arr, mid + 1, high, x);
    } else {
      if (mid - 1 >= low && x > arr[mid - 1])
        return mid;
      else
        return ceilSearch(arr, low, mid - 1, x);
    }
  }

【讨论】:

    【解决方案2】:

    这是一些符合 OP 搜索要求的 C 代码:

    • 值
    • 值包含在数组中:返回索引找到+1
    • 值不在数组中但
    • 值 >= 最后一项:返回数组大小

    它还演示了 4 种不同类型的二进制搜索:

    • 标准二分搜索
    • LessThanEqual 二进制搜索
    • LessThanEqual 或 Last Binary Search
    • NextLargest Binary Search

    (假设data 中没有重复项)

    #include <stdio.h>
    
    int BinarySearch( int key, int data[], const int len )
    {
        int low  = 0;
        int high = len-1;
    
        while( high >= low )
        {
            int mid = low + ((high - low) / 2);
    
            /**/ if (data[mid] < key) low  = mid + 1;
            else if (data[mid] > key) high = mid - 1;
            else return                      mid    ;
        }
        return -1; // KEY_NOT_FOUND
    }
    
    int LessThanEqualBinSearch( int key, int data[], const int len )
    {
        int min = 0;
        int max = len-1;
        // var max = data.length - 1; // Javascript, Java conversion
    
        while( min <= max)
        {
            int mid = min + ((max - min) / 2);
    
            /**/ if (data[mid] < key)  min  = mid + 1;
            else if (data[mid] > key)  max  = mid - 1;
            else   /*data[mid] = key)*/return mid    ;
        }
    
        if( max < 0 )
            return 0;  // key < data[0]
        else
        if( min > (len-1))
            return -1; // key >= data[len-1] // KEY_NOT_FOUND
        else
            return (min < max)
                ? min  
                : max + 1;
    }
    
    int LessThanEqualOrLastBinSearch( int key, int data[], const int len )
    {
        int min = 0;
        int max = len-1;
        // var max = data.length - 1; // Javascript, Java conversion
    
        while( min <= max)
        {
            int mid = min + ((max - min) / 2);
    
            /**/ if (data[mid] < key)  min  = mid + 1;
            else if (data[mid] > key)  max  = mid - 1;
            else   /*data[mid] = key)*/return mid    ;
        }
    
        if( max < 0 )
            return 0;     // key < data[0]
        else
        if( min > (len-1))
            return len-1; // key >= data[len-1]
        else
            return (min < max)
                ? min  
                : max + 1;
    }
    
    int NextLargestBinSearch( int key, int data[], const int len )
    {
        int low  = 0;
        int high = len-1;
    
        while( low <= high)
        {
            // To convert to Javascript:
            // var mid = low + ((high - low) / 2) | 0;
            int mid = low + ((high - low) / 2);
    
            /**/ if (data[mid] < key) low  = mid + 1;
            else if (data[mid] > key) high = mid - 1;
            else return                      mid + 1;
        }
    
        if( high < 0 )
            return 0;   // key < data[0]
        else
        if( low > (len-1))
            return len; // key >= data[len-1]
        else
            return (low < high)
                ? low  + 1
                : high + 1;
    }
    
    int main()
    {
        int items[] = { 1, 3, 5, 7, 9, 11 };
        int LENGTH  = sizeof(items) / sizeof(items[0]);
    
        for( int i = -1; i < 14; ++i )
            printf( "[%2d]: == %2d   <= %2d   <| %d   > %d\n", i
            , BinarySearch                ( i, items, LENGTH )
            , LessThanEqualBinSearch      ( i, items, LENGTH )
            , LessThanEqualOrLastBinSearch( i, items, LENGTH )
            , NextLargestBinSearch        ( i, items, LENGTH )
        );   
    
        return 0;
    }
    

    输出:

    [-1]: == -1   <=  0   <| 0   > 0
    [ 0]: == -1   <=  0   <| 0   > 0
    [ 1]: ==  0   <=  0   <| 0   > 1
    [ 2]: == -1   <=  1   <| 1   > 1
    [ 3]: ==  1   <=  1   <| 1   > 2
    [ 4]: == -1   <=  2   <| 2   > 2
    [ 5]: ==  2   <=  2   <| 2   > 3
    [ 6]: == -1   <=  3   <| 3   > 3
    [ 7]: ==  3   <=  3   <| 3   > 4
    [ 8]: == -1   <=  4   <| 4   > 4
    [ 9]: ==  4   <=  4   <| 4   > 5
    [10]: == -1   <=  5   <| 5   > 5
    [11]: ==  5   <=  5   <| 5   > 6
    [12]: == -1   <= -1   <| 5   > 6
    [13]: == -1   <= -1   <| 5   > 6
    
    • 1st 列是标准的二分搜索
    • 2nd 列是小于二分搜索
    • 3rd 列是小于或最后二进制搜索
    • 4th 列是下一个最大的二分搜索

    【讨论】:

      【解决方案3】:

      这就是你想要的。它返回下一个更大的元素。

      public int binarySearch(int[] arr, int key) {
          int lo = 0;
          int hi = arr.length - 1;int mid = 0;
          while (lo <= hi) {
              mid = (lo + hi) / 2;
              if      (key < arr[mid]) hi = mid - 1;
              else if (key > arr[mid]) lo = mid + 1;
              else return mid;
          }
          return -Math.min(lo, hi)-2;
      }
      
      
      public int myBinarySearch(int[] arr, int key){
           int x = binarySearch(arr, key);
           if(x >= arr.length-1 || -x > arr.length){
               //whatever you want to return
               return Integer.MAX_VALUE;
           }
           else if(x >= 0)
                return arr[x+1] ;
           else
                return arr[-x-1];
      }
      public static void main(String args[]) {
          Triall tr = new Triall();
          int arr[] = { 1, 3, 5, 7, 9, 11 }; 
          for( int i = 0; i < 13; i++ ) { 
              int n = tr.myBinarySearch( arr,i ); 
              System.out.println(i + " " + n ); 
          }
      }
      

      【讨论】:

      • 实际上我想实现我的二进制搜索版本而不是使用 Collections.binarySearch()
      • @smttsp 这仅适用于数组中没有重复项的情况。如果您有三个相同的项目,并且二进制搜索返回其中的第一个或第二个,那么您的方法将不会返回下一个更大的项目。在二分查找之后,你必须向上扫描数组以寻找不同的值。
      • 我发现这行不通。至少可以帮助您找到一些东西:)
      • 这段代码仍然很糟糕:int arr[] = { 1, 3, 5, 7, 9, 11 }; for( int i = 0; i
      • @Michaelangelo,你是对的,它现在正在工作。感谢您指出我的错误
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-27
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 2019-08-26
      • 1970-01-01
      相关资源
      最近更新 更多