C++ 查找排序数组中比给定值最小和最大的元素的二进制搜索?

C++ 查找排序数组中比给定值最小和最大的元素的二进制搜索?,c++,algorithm,binary-search,C++,Algorithm,Binary Search,因此,我试图实现二进制搜索算法(尽可能通用,可以适应不同的情况)。我在互联网上搜索了这个,一些人使用,while(low!=high)还有一些人使用,while(low>n; 对于(int i=0;i>arr1[i]; 排序(arr1,arr1+n); coutval1; coutval2; int ans1=二进制搜索1(val1); int ans2=二进制搜索2(val2); cout要部分回答这个问题,可以根据要搜索的是比元素大的第一个元素还是比元素小的第一个元素(使用回调函数或类似函数

因此,我试图实现二进制搜索算法(尽可能通用,可以适应不同的情况)。我在互联网上搜索了这个,一些人使用,
while(low!=high)
还有一些人使用,
while(low>n;
对于(int i=0;i>arr1[i];
排序(arr1,arr1+n);
coutval1;
coutval2;
int ans1=二进制搜索1(val1);
int ans2=二进制搜索2(val2);

cout要部分回答这个问题,可以根据要搜索的是比元素大的第一个元素还是比元素小的第一个元素(使用回调函数或类似函数)计算出实际的比较。但是,在第一个代码块中,您使用

arr[mid] <= val && arr[mid+1] > val
arr[mid]val
在第二个块中,索引在第二个条件下移动

if (arr[mid] >= val && arr[mid] < val)
if(arr[mid]>=val&&arr[mid]

省略,这似乎不一致。

下面是一个通用算法,给定元素的排序范围和值,它返回一对迭代器,其中第一个迭代器的值是排序范围内比较小于输入值的第一个元素,第二个迭代器的值是第一个元素in比较大于输入值的范围

若返回的迭代器对指向范围的末尾,则表示输入的范围为空

我已经尽可能地使它通用化,它还处理边缘案例和重复

template<typename BidirectionalIterator>
std::pair<BidirectionalIterator, BidirectionalIterator>
lowhigh(BidirectionalIterator first, BidirectionalIterator last,
        typename std::iterator_traits<BidirectionalIterator>::value_type const &val) {
  if(first != last) {
    auto low = std::lower_bound(first, last, val);
    if(low == last) {
      --last;
      return std::make_pair(last, last);
    } else if(low == first) {
     if(first != last - 1) {
        return std::make_pair(first, std::upper_bound(low, last - 1, val) + 1);   
      } else {
        return std::make_pair(first, first);  
      }
    } else {
      auto up = std::upper_bound(low, last, val);
      return (up == last)? std::make_pair(low - 1, up - 1) : std::make_pair(low - 1, up);
    }
  }
  return std::make_pair(last, last);
}
模板
std::pair
低-高(首先是双向运算符,最后是双向运算符,
类型名称std::迭代器特征::值类型const&val){
如果(第一个!=最后一个){
自动低=标准::下限(第一个、最后一个、val);
如果(低==上一个){
--最后;
返回std::make_对(last,last);
}else if(低==第一个){
如果(第一个!=最后一个-1){
返回std::make_pair(第一,std::上限(下限,最后-1,val)+1);
}否则{
返回std::make_对(第一,第一);
}
}否则{
自动向上=标准::上限(下限、下限、下限);
return(up==last)?std::make_对(low-1,up-1):std::make_对(low-1,up);
}
}
返回std::make_对(last,last);
}

< P>编写正确的程序是困难的。一旦程序被验证为正确,它就必须被修改很少,并且重用更多。在这一行中,假定您使用C++而不是C,我建议您尽可能充分使用STD C++库。算法

为你做的魔术,并给予可怕的力量,模板你应该能够使用这些方法,只要添加其他方法,将实现排序


HTH.

您的搜索例程有一些bug[其中一个完全被破坏了]。我已经清理了一些bug,但我是从您的代码开始的。注意:不保证--现在已经晚了,但这应该给您一个起点。注意“lo/hi”是标准术语(例如,lo是您的开始,hi是您的结束)。此外,请注意,hi/lo设置为mid,而不是mid+1或mid-1


有一些边缘情况需要处理。while循环必须“正如你所说,有不同的方法来表示二进制搜索的结束条件,这完全取决于你的两个极限是什么意思。让我解释一下我的极限,我认为它很容易理解,并且可以让你在其他情况下修改它,而不必考虑太多

让我先把这两个极限称为第一个极限和最后一个极限。我们要找到大于某个x的第一个元素。以下不变量将始终保持不变:

超过最后一个元素的每一个元素都大于x,并且超过前一个元素的每一个元素都大于x 第一个较小或相等(相反的情况)

请注意,不变量没有说明任何关于间隔[first,last]的内容。在不进一步了解向量的情况下,限制的唯一有效初始化是向量的first=0和last=last位置。这满足了条件,因为last之后没有任何内容,first之前也没有内容,所以一切都是正确的

由于间隔[first,last]未知,因此我们必须继续进行,直到其为空,从而更新限制

int get_first_more(常量std::vector&v,int x)
{
int first=0,last=int(v.size())-1;
while(第一个x)
last=mid-1;
其他的
第一个=中间+1;
}
返回last+1==v.size()?-1:last+1;
}
如您所见,我们只需要两种情况,因此代码非常简单。每次检查时,我们都会更新限制以始终保持不变值为真

当循环结束时,使用不变量,我们知道last+1大于x,如果它存在,那么我们只需要检查是否仍在向量内

记住这一点,您可以根据需要修改二进制搜索。让我们更改它以查找最后一个小于x的值。我们更改不变量:

第一个元素之前的每个元素都小于x,并且每个元素 last之后大于或等于x

因此,修改代码非常容易:

int get\u last\u较小(const std::vector&v,int x)
{
int first=0,last=int(v.size())-1;
while(first=x)
last=mid-1;
其他的
第一个=中间+1;
}
返回first-1<0-1:first-1;
}

检查我们是否只更改了运算符(>=而不是>)和返回,使用与以前相同的参数。

请告诉我您已经为这些任务创建了一个函数…发布完整的代码。如果没有这样的元素,预期的行为是什么?如果没有这样的元素,它应该返回-1。我在编写这样的二进制搜索时感到困惑,因此我不知道在哪里编写它。我该怎么做ly?@KarolyHorvath,添加了完整的代码。搜索
下限()
上限()
。此代码假设没有重复的元素
if (arr[mid] >= val && arr[mid] < val)
template<typename BidirectionalIterator>
std::pair<BidirectionalIterator, BidirectionalIterator>
lowhigh(BidirectionalIterator first, BidirectionalIterator last,
        typename std::iterator_traits<BidirectionalIterator>::value_type const &val) {
  if(first != last) {
    auto low = std::lower_bound(first, last, val);
    if(low == last) {
      --last;
      return std::make_pair(last, last);
    } else if(low == first) {
     if(first != last - 1) {
        return std::make_pair(first, std::upper_bound(low, last - 1, val) + 1);   
      } else {
        return std::make_pair(first, first);  
      }
    } else {
      auto up = std::upper_bound(low, last, val);
      return (up == last)? std::make_pair(low - 1, up - 1) : std::make_pair(low - 1, up);
    }
  }
  return std::make_pair(last, last);
}
int
binarysearch_larger(const int *arr,int cnt,int val)
// arr -- array to search
// cnt -- number of elements in array
// val -- desired value to be searched for
{
    int mid;
    int lo;
    int hi;
    int match;

    lo = 0;
    hi = cnt - 1;

    match = -1;

    while (lo < hi) {
        mid = (hi + lo) / 2;

        if (arr[mid] <= val) && (arr[mid+1] > val)) {
            if ((mid + 1) < cnt)
                match = mid + 1;
            break;
        }

        if (arr[mid] > val)
            hi = mid;
        else
            lo = mid;
    }

    return match;
}

int
binarysearch_smaller(const int *arr,int cnt,int val)
// arr -- array to search
// cnt -- number of elements in array
// val -- desired value to be searched for
{
    int mid;
    int lo;
    int hi;
    int match;

    lo = 0;
    hi = cnt - 1;

    match = -1;

    while (lo < hi) {
        mid = (hi + lo) / 2;

        if (arr[mid] <= val) && (arr[mid+1] > val)) {
            match = mid;
            break;
        }

        if (arr[mid] > val)
            hi = mid;
        else
            lo = mid;
    }

    // the condition here could be "<=" or "<" as you prefer
    if ((match < 0) && (arr[cnt - 1] <= val))
        match = cnt - 1;

    return match;
}
int get_last_smaller(const std::vector<int>& v, int x)
{
  int first = 0, last = int(v.size()) - 1;
  while (first <= last)
  {
    int mid = (first + last) / 2;
    if (v[mid] >= x)
      last = mid - 1;
    else
      first = mid + 1;
  }
  return first - 1 < 0 ? -1 : first - 1;
}