C++ 我可以在函数调用上使用std::lower_bound而不是迭代器吗?
简单用例:我想通过二进制搜索找到最小索引C++ 我可以在函数调用上使用std::lower_bound而不是迭代器吗?,c++,algorithm,std,binary-search,C++,Algorithm,Std,Binary Search,简单用例:我想通过二进制搜索找到最小索引I,其中f(I)>=t,其中t是一些阈值,f是整数值上的单调递增函数 一个简单的方法是对每个可能的输入调用这个函数,将它保存到一个容器中,然后使用下限,这在我想用不同的阈值对同一个函数进行多个搜索的情况下非常有用 然而,在我的场景中,函数求值在运行时非常昂贵,并且我有多个不同的函数/lambda,我只对它们执行一个二进制搜索 所以我想,我需要的是一个下限函数,它接受一个函数和一个值范围,而不是开始和结束迭代器,或者我需要一种机制来隐藏迭代器结构中的函数调用
I
,其中f(I)>=t
,其中t
是一些阈值,f
是整数值上的单调递增函数
一个简单的方法是对每个可能的输入调用这个函数,将它保存到一个容器中,然后使用下限
,这在我想用不同的阈值对同一个函数进行多个搜索的情况下非常有用
然而,在我的场景中,函数求值在运行时非常昂贵,并且我有多个不同的函数/lambda,我只对它们执行一个二进制搜索
所以我想,我需要的是一个下限
函数,它接受一个函数和一个值范围,而不是开始和结束迭代器,或者我需要一种机制来隐藏迭代器结构中的函数调用。我知道第一个解决方案很容易实现,但我希望有一个解决方案可以避免从头开始实现二进制搜索
对我来说,这似乎是一个常见的用例,但不知何故,我在网上找不到关于这个特定问题的任何东西。我很感激任何提示、技巧和链接
编辑
我发现这两个最初提供的解决方案非常有趣。使用comp
参数给出的解决方案非常优雅,但是我忘了提到这种方法不适用于我的原因。除了单个函数评估的长运行时间外,我还存在搜索空间大的问题(例如,超过10**15
整数),这使得为此分配虚拟向量不切实际。我不知道如何使用boost
增量迭代器,但无论如何,我只需要使用std
即可
不过,使用自定义迭代器的第二个解决方案非常冗长。我用我提到的大量数据测试了它(并将int
s改为long
s),但这似乎也很慢。似乎lower_-bound
实际上多次调用操作符+++
,从一个位置转到另一个位置,因此std::lower_-bound
的实现可能已经是我这里的方法的杀手(请参见下面修改的代码示例和输出),并且没有办法绕过自定义实现(我已经有了,这里不需要)
不过,谢谢你的见解,这两个答案都给了我一些新的启示。也许有人可以对上面提到的几点有更多的了解,因为我绝对不是迭代器或下限的实现方面的专家,也许我用错了,或者是@idclev给出的代码示例让它在通过那些我不认识的数字,我的工作效率很低
修改的代码示例
#包括
#包括
#包括
longlongfoo(longlongi){std::cout正如@KamilCuk所建议的,编写自己的迭代器,或者
您可以使用自然数的任何容器(如果您手头没有范围,只需创建一个std::vector
,并用单调增长的数字填充它-前提是您至少知道预期值所在的预期间隔的边界)。接下来,std::lower_bound
接受一个comp
参数:
std::向量args(1000);
std::iota(args.begin(),args.end(),0);
root=std::下限(args.cbegin(),args.cend(),t,
[](intx,intt){返回f(x)
(作为一项完整性检查,检查root
是否是args
的开始-然后0可以高于所需的根-或者是args
的结束-然后根高于估计的右边界。)您可以编写自己的迭代器,为了避免对函数进行不必要的计算,可以使用记忆。迭代器可以有一个静态映射来缓存函数调用的结果。为了使不同函数的迭代器具有不同的类型,我在函数指针上对迭代器进行了参数化:
#include <iostream>
#include <unordered_map>
#include <algorithm>
double foo(int i){ return i;}
using function_type = double(*)(int);
template <function_type F>
struct fun_iterator {
using difference_type = size_t;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::forward_iterator_tag;
static std::unordered_map<int,double> m;
int index;
fun_iterator(int index) : index(index) {}
fun_iterator& operator++() {
++index;
return *this;
}
fun_iterator operator++(int x) {
fun_iterator it = *this;
++index;
return it;
}
int operator*() {
auto it = m.find(index);
if (it != m.end()) return it->second;
auto res = F(index);
m[index] = res;
return res;
}
bool operator!=(const fun_iterator& other){
return index != other.index;
}
bool operator==(const fun_iterator& other){
return index == other.index;
}
bool operator<(const fun_iterator& other){
return index < other.index;
}
};
template <function_type F>
std::unordered_map<int,double> fun_iterator<F>::m;
template <function_type F>
std::pair<fun_iterator<F>,fun_iterator<F>> make_begin_and_end(int begin,int end){
return {{begin},{end}};
}
int main() {
auto x = make_begin_and_end<foo>(0,100);
auto it = std::lower_bound(x.first,x.second,50);
std::cout << it.index;
}
#包括
#包括
#包括
双foo(inti){return i;}
使用函数_type=double(*)(int);
模板
结构乐趣迭代器{
使用差异类型=大小t;
使用value_type=int;
使用指针=int*;
使用reference=int&;
使用迭代器\u category=std::forward\u迭代器\u标记;
静态std::无序映射m;
整数指数;
fun_迭代器(int-index):索引(index){}
fun_迭代器和运算符++(){
++指数;
归还*这个;
}
fun_迭代器运算符++(int x){
乐趣迭代器it=*这;
++指数;
归还它;
}
int运算符*(){
自动it=m.find(索引);
如果(it!=m.end())返回它->秒;
自动恢复=F(索引);
m[指数]=res;
返回res;
}
布尔运算符!=(常量函数迭代器和其他){
返回索引!=其他.index;
}
布尔运算符==(常量函数迭代器和其他){
返回索引==其他索引;
}
bool operatorI会添加向量可以填充std::iota
算法。代替std::vector
,您可以使用:std::lower_bound(boost::counting_迭代器(0),boost::counting_迭代器(1000),…);
。
#include <iostream>
#include <unordered_map>
#include <algorithm>
double foo(int i){ return i;}
using function_type = double(*)(int);
template <function_type F>
struct fun_iterator {
using difference_type = size_t;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::forward_iterator_tag;
static std::unordered_map<int,double> m;
int index;
fun_iterator(int index) : index(index) {}
fun_iterator& operator++() {
++index;
return *this;
}
fun_iterator operator++(int x) {
fun_iterator it = *this;
++index;
return it;
}
int operator*() {
auto it = m.find(index);
if (it != m.end()) return it->second;
auto res = F(index);
m[index] = res;
return res;
}
bool operator!=(const fun_iterator& other){
return index != other.index;
}
bool operator==(const fun_iterator& other){
return index == other.index;
}
bool operator<(const fun_iterator& other){
return index < other.index;
}
};
template <function_type F>
std::unordered_map<int,double> fun_iterator<F>::m;
template <function_type F>
std::pair<fun_iterator<F>,fun_iterator<F>> make_begin_and_end(int begin,int end){
return {{begin},{end}};
}
int main() {
auto x = make_begin_and_end<foo>(0,100);
auto it = std::lower_bound(x.first,x.second,50);
std::cout << it.index;
}