对带/不带提升的函数参数进行二分搜索

binary search over function arguments with/without boost

本文关键字:参数 函数 二分搜索 对带      更新时间:2023-10-16

给定:

typedef .../*some type*/ SomeValue;
SomeValue someFunction(int arg){
     return /*some calculation involving arg that produces SomeValue*/
}
int firstCandidate = 0, lastCandidate = 101;
SomeValue desiredValue = SomeValue();

我想找到int参数,它使用二进制搜索(std::lower_bound(产生desiredValue(当传递给someFunction时(。 firstCandidatelastCandidate是要给someFunction的参数。对于搜索候选人std::lower_bound应调用someFunction(currentArgument)并将结果与desiredValue进行比较。因为SomeValue someFunction(x) < someFunction(x + 1)是真的。

即它应该产生与以下相同的结果:

int findArgLowerbound(int first, int last, SomeValue refVal){
     for (int i = first; i < last; i++){
          if (someFunction(i) >= refVal)
               return i;
     }
     return last;
}

仅使用标准函数+二叉搜索算法。

我如何在有和没有 boost 的情况下轻松做到这一点(无需编写自己的二叉搜索函数(? int不是迭代器,在这种情况下我还没有弄清楚如何进行boost::make_transform_iterator

限制

  1. C++03 标准。
  2. 提升是可以的,但我真的更喜欢没有它的解决方案。

--编辑--

我想知道如何使用内置或已经可用的函数(std::lower_bound 和类似函数(做我想做的事。我可以编写专门的二进制搜索函数,但我认为这不是"正确"的方法。

这是我的处理方式:

假设您有一个已排序的vector<SomeValue>。可以使用someFunction(index)访问此向量。

现在,看看这个。这是二进制搜索的伪代码。继续上面的思考过程,将A[imid]替换为someFunction(imid),并使key成为SomeValue。确保SomeValue具有有效的operator <(或用于代替它的比较器函数(。

当然,这只有在someFunction(x) < someFunction(x + 1)所有x时才有效。你说这是真的,所以它应该是好的。

我建议使用迭代方法,因为两者都具有相同的渐近运行时,并且迭代版本可以更轻松地报告未找到的键,并且倾向于使用更少的内存。

编辑我不知道使用std东西来做到这一点的简单方法。正如你上面提到的,int不能用作迭代器,你可能想要使用的所有函数都需要迭代器。不过,从技术上讲,这些函数中的迭代器是模板化类型,因此您可以编写自己的IntIter类或类似的东西。使用std::lower_bound需要operator *()operator ++()operator +(int)operator *()可能会返回someFunction(n),其中n是与IntIter相关联的 int 值。但是,我不知道这是否真的有效,并且可能需要更多时间和编码。如果你想采用这种方法,你应该看看std::lower_boundstd::advance(在lower_bound中称为(。

想通了(享受宏+模板巫毒教(。

#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/irange.hpp>
#include <boost/typeof/std/utility.hpp>
#include <iomanip>
#include <algorithm>
#include <functional>
#include <sstream>
std::string convertArgs(int arg1, int arg2){
    std::stringstream out;
    out << std::setfill('0') << std::setw(8) << arg1*arg2;
    return out.str();
}
void boostTest(){
    int first = 0, last = 42;
    int arg = 2;
    std::string desiredValue = "00000007";
    BOOST_AUTO(range, boost::irange(first, last));
    BOOST_AUTO(start, boost::make_transform_iterator(range.begin(), std::bind1st(std::ptr_fun(convertArgs), arg)));
    BOOST_AUTO(end, boost::make_transform_iterator(range.end(), std::bind1st(std::ptr_fun(convertArgs), arg)));
    BOOST_AUTO(found, std::lower_bound(start, end, desiredValue));
    if (found != end){
        std::cout << "str:" << *found << "nval: " << *(found.base());
    }
}
int main(int argc, char** argv){
    boostTest();
    return 0;
}

最有可能的是,没有 boost 就无法轻松完成,除非您生成具有所有可能值的数组,自己制作包装迭代器或类似的东西。