簡體   English   中英

二進制搜索以找到數字所在的范圍

[英]Binary search to find the range in which the number lies

我有一個數組

Values array: 12 20 32 40 52
              ^  ^  ^  ^  ^
              0  1  2  3  4

我必須在其上執行二進制搜索才能找到數字所在范圍的索引。 例如:

  1. 給定數字 -> 19(它位於索引 0 和 1 之間),返回 0
  2. 給定數字 -> 22(它位於索引 1 和 2 之間),返回 1
  3. 給定數字 -> 40(它位於索引 3 和 4 之間),返回 3

我以下列方式實現了二分搜索,這對於案例 1 和 3 是正確的,但如果我們搜索案例 2 或 52、55 32 等,則不正確。

#include <iostream>
using namespace std;

int findIndex(int values[], int number, unsigned first, unsigned last)
{
    unsigned midPoint;
    while(first<last)
    {
        unsigned midPoint = (first+last)/2;
        if (number <= values[midPoint])
            last = midPoint -1;
        else if (number > values[midPoint])
            first = midPoint + 1;
    }
    return midPoint;
}


int main()
{
    int a[] = {12, 20, 32, 40, 52};
    unsigned i = findIndex(a, 55, 0, 4);
    cout << i;
}

不允許使用其他變量,例如bool found

C 或 C++ 中的范圍通常以直接指向下限的形式給出,但超過上限。 除非您感到極度自虐,否則您可能也希望在搜索中堅持該慣例。

假設你要遵循那個,你的last = midpoint-1; 是不正確的。 相反,你想最后設定為一個過去你要真正使用范圍的結束,所以它應該是last = midpoint;

你也只需要一個比較,而不是兩個。 在二分查找中,只要兩個邊界不相等,您將把下限或上限設置為中心點,因此您只需要進行一次比較就可以決定哪個。

至少按照慣例,在 C++ 中,您使用<而不是<=>等進行所有比較。上述任何一種都可以工作,但遵循僅使用<的約定可避免對包含的類型強加額外的(不必要的)要求.

雖然大多數面試官可能並不關心,但當你做midpoint = (left + right)/2;時也有潛在的溢出midpoint = (left + right)/2; . 我通常更喜歡midpoint = left + (right - left)/2;

考慮到這些,代碼可能如下所示:

template <class T>
T *lower_bound(T *left, T *right, T val) {
    while (left < right) {
        T *middle = left + (right - left) / 2;
        if (*middle < val)
            left = middle + 1;
        else
            right = middle;
    }
    return left;
}

template <class T>
T *upper_bound(T *left, T *right, T val) {
    while (left < right) {
        T *middle = left + (right - left) / 2;
        if (val < *middle)
            right = middle;
        else
            left = middle + 1;
    }
    return left;
}

為什么不使用標准庫函數?

#include <vector>
#include <algorithm>
#include <iostream>

using namespace std;

int main() {
    for (int input = 10; input < 55; input++) {
        cout << input << ": ";

        // Your desire:
        vector<int> v = { 12, 20, 32, 40, 52 };
        if (input < v.front() || input > v.back()) {
            cout << "Not found" << endl;
        } else {
            auto it = upper_bound(v.begin(), v.end(), input);
            cout << it - v.begin() - 1 << endl;
        }
    }
}

注意:一個非常酷的網站 - http://en.cppreference.com/w/cpp/algorithm

這將在min(A[i]) <= key <=max(A[i])

int binary_search(int A[],int key,int left, int right)
{

  while (left <= right) {
        int middle = left + (right - left) / 2;
        if (A[middle] < key)
            left = middle+1;
        else if(A[middle] > key)
            right = middle-1;
        else
            return middle;
    }
    return (left - 1);
}

對於輸入

4

1 3 8 10

4

輸出

3(3 和 8 中的最小值)

#include <stdio.h>

int main()
{
   int c, first, last, middle, n, search, array[100];


   scanf("%d",&n);



for (c = 0; c < n; c++)
  scanf("%d",&array[c]);


   scanf("%d", &search);

   first = 0;
   last = n - 1;
   middle = (first+last)/2;

while (first <= last) {

  if (array[middle] < search)
  { 
     first = middle + 1;    }
  else if (array[middle] == search) {

     break;
  }
  else
  {  
     last = middle - 1;
  }

  middle = (first + last)/2;
 }
  printf("%d\n",array[middle]);
   return 0;   
 }

對成功的常規二分搜索返回鍵的索引。 如果找不到鍵,它總是停在比我們正在搜索的鍵大的最低鍵的索引處。 我想以下修改后的二進制搜索算法會起作用。

Given sorted array A
Find a key using binary search and get an index. 
If A[index] == key
    return index;
else 
   while(index > 1 && A[index] == A[index -1]) index = index -1;
   return index;
binsrch(array, num, low, high) {
if (num > array[high])
     return high;


while(1) {
     if (low == high-1)
          return low;
     if(low >= high)
          return low-1;        
     mid = (low+high)/2
     if (num < arr[mid])
          high = mid;
     else
          low = mid+1;
    }
}

這是一個更具體的答案

int findIndex(int values[],int key,int first, int last)
{
    if(values[first]<=key && values[first+1]>=key)// stopping condition
    {
        return first;
    }

   int imid=first+(last-first)/2;

   if(first==last || imid==first)
   {
        return -1;
   }
   if(values[imid]>key)
   {
        return findIndex(values,key,first,imid);
    }
    else if(values[imid]<=key)
    {
        return findIndex(values,key,imid,last);
    }

}

我覺得這更符合你正在尋找的東西......我們不會在這件事的最后一個價值上胡說八道

/* binary_range.c (c) 2016 adolfo@di-mare.com  */
/* http://stackoverflow.com/questions/10935635 */

/* This code is written to be easily translated to Fortran */

#include <stdio.h>   /* printf() */
#include <assert.h>  /* assert() */

/** Find the biggest index 'i' such that '*nSEED <= nVEC[i]'.
    - nVEC[0..N-1] is an strict ascending order array.
    - Returns and index in [0..N].
    - Returns 'N' when '*nSEED>nVEC[N-1]'.
    - Uses binary search to find the range for '*nSEED'.
*/
int binary_range( int *nSEED, int nVEC[] , int N ) {
    int lo,hi, mid,plus;

    if ( *nSEED > nVEC[N-1] ) {
        return N;
    }
    for (;;) { /* lo = binary_range_search() */
        lo = 0;
        hi = N-1;
        for (;;) {
            plus = (hi-lo)>>1; /* mid = (hi+lo)/2; */
            if ( plus == 0 ) {   assert( hi-lo==1 );
                if (*nSEED <= nVEC[lo]) {
                    hi = lo;
                }
                else {
                    lo = hi;
                }
            }
            mid = lo + plus; /* mid = lo + (hi-lo)/2; */

            if (*nSEED <= nVEC[mid]) {
                hi = mid;
            }
            else {
                lo = mid;
            }
            if (lo>=hi) { break; }
        }
        break;
    } /* 'lo' is the index */
    /* This implementation does not use division. */
    /* =========================================  */

    assert( *nSEED <= nVEC[lo] );
    return lo;
}

/** Find the biggest index 'i' such that '*nSEED <= nVEC[i]'.
    - nVEC[0..N-1] is an strict ascending order array.
    - Returns and index in [0..N].
    - Returns 'N' when '*nSEED>nVEC[N-1]'.
    - Uses sequential search to find the range for '*nSEED'.
*/
int sequential_range( int* nSEED, int nVEC[] , int N ) {
    int i;
    if ( *nSEED > nVEC[N-1] ) {
        return N;
    }
    i=0;
    while ( i<N ) {
        if ( *nSEED <= nVEC[i] ) { break; }
        ++i;
    }
    return i;
}

/** test->stackoverflow.10935635(). */
void test_10935635() {
{{  /* test.stackoverflow.10935635()                                  */
    /* http://stackoverflow.com/questions/10935635                    */
    /* binary_range search to find the range in which the number lies */
    /*              0  1  2  3  4                                     */
    int nVEC[] = { 12,20,32,40,52 }; int val;
    int N = sizeof(nVEC)/sizeof(nVEC[0]); /* N = DIM(nVEC[]) */

    val=19; val   = binary_range( &val,nVEC,N );

    /* 19 -> [12 < (19) <= 20] -> return 1 */
    val=19; assert( binary_range( &val,nVEC,N ) == 1 );

    /* 22 -> [20 < (22) <= 32] -> return 2 */
    val=22; assert( binary_range( &val,nVEC,N ) == 2 );

    /* 40 -> [32 < (40) <= 40] -> return 3 */
    val=40; assert( binary_range( &val,nVEC,N ) == 3 );

    /* Everything over 52 returns N */
    val=53; assert( binary_range( &val,nVEC,N ) == N );
}}
}

/** Test program. */
int main() {
    if (1) {
        printf( "\ntest_10935635()" );
        test_10935635();
    }
    printf( "\nEND" );
    return 0;
}

/* Compiler: gcc.exe (tdm-1) 4.9.2 */
/* IDE:      Code::Blocks 16.01    */
/* Language: C && C++              */

/* EOF: binary_range.c */

我知道這是一個舊線程,但由於我必須解決類似的問題,所以我想我會分享它。 給定一組不重疊的整數范圍,我需要測試給定的值是否位於這些范圍中的任何一個。 以下(在 Java 中)使用修改后的二分搜索來測試值是否位於已排序(從最低到最高)的整數范圍集合內。

/**
 * Very basic Range representation for long values
 *
 */
public class Range {

private long low;
private long high;

public Range(long low, long high) {
    this.low = low;
    this.high = high;
}

public boolean isInRange(long val) {
    return val >= low && val <= high;
}

public long getLow() {
    return low;
}

public void setLow(long low) {
    this.low = low;
}

public long getHigh() {
    return high;
}

public void setHigh(long high) {
    this.high = high;
}

@Override
public String toString() {
    return "Range [low=" + low + ", high=" + high + "]";
}
}



import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//Java implementation of iterative Binary Search over Ranges
class BinaryRangeSearch { 
// Returns index of x if it is present in the list of Range, 
// else return -1 
int binarySearch(List<Range> ranges, int x) 
{ 

    Range[] arr = new Range[ranges.size()];
    arr = ranges.toArray(arr);
    int low = 0, high = arr.length - 1; 
    int iters = 0;
    while (low <= high) { 
        int mid = low + (high - low) / 2; // find mid point

        // Check if x is present a
        if (arr[mid].getLow() == x) {
            System.out.println(iters + " iterations");
            return mid;                 
        }

        // If x greater, ignore left half 
        if (x > arr[mid].getHigh()) {
            low = mid + 1; 
        }
        else if (x >= arr[mid].getLow()) {
            System.out.println(iters + " iterations");
            return mid;
        }

        // If x is smaller, ignore right half of remaining Ranges
        else
            high = mid - 1; 
        iters++;
    } 

    return -1; // not in any of the given Ranges
} 

// Driver method to test above 
public static void main(String args[]) 
{ 
    BinaryRangeSearch ob = new BinaryRangeSearch(); 

    // make a test list of long Range
    int multiplier = 1;

    List<Range> ranges = new ArrayList<>();
    int high = 0;
    for(int i = 0; i <7; i++) {

        int low = i + high;
        high = (i+10) * multiplier;
        Range r = new Range(low, high);
        multiplier *= 10;
        ranges.add(r);
    }

    System.out.println(Arrays.toString(ranges.toArray()));

    int result = ob.binarySearch(ranges, 11); 
    if (result == -1) 
        System.out.println("Element not present"); 
    else
        System.out.println("Element found at "
                        + "index " + result); 
} 
} 

我的python實現:

時間復雜度:O(log(n)) 空間復雜度:O(log(n))

def searchForRange(array, target):
    range = [-1, -1]
    alteredBinarySerach(array, target, 0, len(array) -1, range, True)
    alteredBinarySerach(array, target, 0, len(array) -1, range, False)
    return range

def alteredBinarySerach(array, target, left, right, range, goLeft):
    if left > right:
        return

    middle = (left+ right)//2

    if array[middle] > target:
        alteredBinarySerach(array, target, left, middle -1, range, goLeft)
    elif array[middle] < target:
        alteredBinarySerach(array, target, middle +1, right, range, goLeft)
    else:
        if goLeft:
            if middle == 0 or array[middle -1] != target:
                range[0] = middle
            else:
                alteredBinarySerach(array, target, left, middle -1 , range, goLeft)
        else:
            if middle == len(array) -1 or array[middle+1] != target:
                range[1] = middle
            else:
                alteredBinarySerach(array, target, middle +1, right , range, goLeft)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM