我有一个数组
Values array: 12 20 32 40 52
^ ^ ^ ^ ^
0 1 2 3 4
我必须执行二进制搜索才能找到数字所在范围的索引。例如:
我以下面的方式实现了二进制搜索,这对于案例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
。
答案 0 :(得分:13)
C或C ++中的范围通常被指定为直接指向下限,但是超过上限。除非你感到极度自虐,否则你可能也想在搜索中坚持这个惯例。
假设你要遵循这一点,你的last = midpoint-1;
是不正确的。相反,您希望将最后一个过去设置为您将要实际使用的范围的结尾,因此它应该是last = midpoint;
您也只需要一个比较,而不是两个。在二元搜索中,只要两个边界不相等,您就可以设置中心点的下限或上限,因此您只需要进行一次比较来决定哪个。
至少按照惯例,在C ++中,您使用<
代替<=
,>
等进行所有比较。以上任何一种都可以使用,但遵循惯例仅使用<
不会对所包含的类型强加额外(不必要的)要求。
虽然大多数面试官可能都不在乎,但当你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;
}
答案 1 :(得分:2)
为什么不使用标准库函数?
#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
答案 2 :(得分:1)
INPUT
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;
}
答案 3 :(得分: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;
答案 4 :(得分:0)
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;
}
}
答案 5 :(得分:0)
这将在 min(A [i])&lt; = key&lt; = 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);
}
答案 6 :(得分:0)
这是一个更具体的答案
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);
}
}
我觉得这更符合你所寻找的内容......而且我们不会废弃这个东西中的最后一个值
答案 7 :(得分:0)
/* 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 */
答案 8 :(得分:0)
我知道这是一个旧线程,但是由于我不得不解决类似的问题,所以我认为我会分享它。给定一组不重叠的整数范围,我需要测试给定值是否位于这些范围中的任何一个范围内。以下(在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);
}
}
答案 9 :(得分:0)
我的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)