C++ 使用std::equal_range在某些范围内搜索向量
我有一个std::vector,元素是成对的,需要找到第一个分量在某些范围内的所有元素,例如,要找到所有元素,比如abs(第一个分量的值-参考)我认为你应该在函数C++ 使用std::equal_range在某些范围内搜索向量,c++,search,stl,C++,Search,Stl,我有一个std::vector,元素是成对的,需要找到第一个分量在某些范围内的所有元素,例如,要找到所有元素,比如abs(第一个分量的值-参考)我认为你应该在函数comp()中使用fabs而不是abs相等范围需要排序范围 比较函数隐含的顺序与将范围排序到的顺序不匹配,因此对equal\u range的调用具有未定义的行为 例如,假设您的列表包含{.5,0},{.6,0}(这些已排序),然后您将std::bind(comp({.5,5},_1))应用于每个元素 comp({.5,5},{.5,0}
comp()中使用fabs
而不是abs
相等范围
需要排序范围
比较函数隐含的顺序与将范围排序到的顺序不匹配,因此对equal\u range
的调用具有未定义的行为
例如,假设您的列表包含{.5,0},{.6,0}
(这些已排序),然后您将std::bind(comp({.5,5},_1))
应用于每个元素
comp({.5,5},{.5,0})
将返回true
comp({.5,5},{.6,0})
将返回false
您的排序顺序是:“.5
小于.6
”,但同时您的comp
函数是“.6
小于.5
”(因为存在一个小于.5
但不小于.6
)的值。这是矛盾的,也是你问题的原因
要实际查找所有元素,例如
std::bind(comp({.5,.5},_1))
返回true,您可以使用std::copy_if(data.begin()、data.end()、一些输出迭代器、std::bind(comp(ref,std::placeholders::_1))
(尽管有多种不同的方法,具体取决于您的需要).您的比较函数不满足严格弱排序的要求,即对于两个元素,例如a和b,如果comp(a,b)=true
,则comp(b,a)
应为false
你可能想要更像这样的东西:
struct Comp {
double target;
bool operator()(const pair<double, double>& lhs,
const pair<double, double>& rhs) const {
return abs(lhs.first - target) < abs(rhs.first - target);
}
};
vector< pair<double, double> > data;
data.push_back(make_pair(0.1, 1.0));
data.push_back(make_pair(0.15, 1.2));
data.push_back(make_pair(0.189, 2.1));
data.push_back(make_pair(0.19, -2.1));
data.push_back(make_pair(0.192, 3.1));
data.push_back(make_pair(0.2, 0.1));
data.push_back(make_pair(0.205, 0.1));
data.push_back(make_pair(0.205, 0.0));
data.push_back(make_pair(0.206, 12.1));
data.push_back(make_pair(0.21, -12.9));
data.push_back(make_pair(0.3, 3.4));
data.push_back(make_pair(0.5, 7.5));
// We *must* sort the vector using the same comparison function that we're
// about to use to get the lower and upper bounds
Comp comp;
comp.target = 0.2;
sort(data.begin(), data.end(), comp);
// Get the lower bound
pair<double, double> low(make_pair(comp.target, 0.0));
vector< pair<double, double> >::iterator lower =
lower_bound(data.begin(), data.end(), low, comp);
// Get the upper bound
pair<double, double> up(make_pair(comp.target + 0.01, 0.0));
// N.B. use "lower_bound" here to get upper bound of target + 0.01 exclusive.
// If we want to include target + 0.01, use "upper_bound"
vector< pair<double, double> >::iterator upper =
lower_bound(data.begin(), data.end(), up, comp);
for_each(lower, upper, [](const pair<double, double> &data_point) {
cout << data_point.first << "\t" << data_point.second << "\n";
});
未能初始化
a
和b
不会随机初始化它们-读取未初始化的值会调用未定义的行为。嗨,Mankarse,a和b是随机初始化的,我只是懒得在那里显示代码。对不起。无论如何,因为向量中只有10个元素,我把它们打印出来,然后一个一个地比较,但是,由于反馈,搜索算法还是不起作用。但是abs的原型在我的编译器中接受双值并返回双精度。无论如何,我也尝试了fabs,但不起作用,但是abs是一个模板函数,它接受双类型参数,这让人困惑。那么,有没有办法修改代码以找到所需的元素?@user1285419:您可以使用std::partition(data.begin(),data.end(),std::bind(comp(ref,std::placeholders::_1))
。如果这样做,则不需要对向量进行排序。您需要的结果将介于data.begin()
和std::partition
的返回值之间。谢谢。使用std::partition可以工作,但速度太慢了。在我的例子中,向量包含200000多个元素,搜索过程将重复多次。@user1285419:std::partition
具有线性时间复杂度。它渐进地优于您使用的“排序-然后-相等范围”方法。它也是渐近最优的(每个元素必须至少访问一次才能找到满足谓词的所有元素)。(也就是说,可能还有更好的方法来实现您正朝着的实际最终结果)。我现在使用的方法只是首先对向量进行排序,然后通过循环搜索满足要求的元素,因为向量已排序,当我们到达大于参考差的元素时,打破循环。我不知道这是否好,但将其与std::partition进行比较,似乎分区所需的时间是std::partition的两倍。但无论如何,我的路还是太慢了,我仍然在寻找更快的路。谢谢弗雷泽。我为以下数据集(0.1,1.0),(0.15,1.2),(0.189,2.1),(0.19,-2.1),(0.192,3.1),(0.2,0.1),(0.205,0.1),(0.205,0.0),(0.206,12.1),(0.21,-12.9),(0.3,3.4),(0.5,7.5)尝试了您的代码。我正在搜索x分量在0.19到0.21之间的所有点,即目标=0.2,它假定给我以下点,但它显示的结果实际上是空的(0.189,2.1),(0.19,-2.1),(0.192,3.1),(0.2,0.1),(0.205,0.1),(0.205,0.0),(0.206,12.1),(0.21,-12.9)。我编辑了答案,以匹配上面的数据。这对我来说很好。(0.189,2.1)不应包含在结果中,因为它与目标值的距离大于0.01。(0.19,-2.1)被排除,因为您指定了<0.01
,而不是
struct Comp {
double target;
bool operator()(const pair<double, double>& lhs,
const pair<double, double>& rhs) const {
return abs(lhs.first - target) < abs(rhs.first - target);
}
};
vector< pair<double, double> > data;
data.push_back(make_pair(0.1, 1.0));
data.push_back(make_pair(0.15, 1.2));
data.push_back(make_pair(0.189, 2.1));
data.push_back(make_pair(0.19, -2.1));
data.push_back(make_pair(0.192, 3.1));
data.push_back(make_pair(0.2, 0.1));
data.push_back(make_pair(0.205, 0.1));
data.push_back(make_pair(0.205, 0.0));
data.push_back(make_pair(0.206, 12.1));
data.push_back(make_pair(0.21, -12.9));
data.push_back(make_pair(0.3, 3.4));
data.push_back(make_pair(0.5, 7.5));
// We *must* sort the vector using the same comparison function that we're
// about to use to get the lower and upper bounds
Comp comp;
comp.target = 0.2;
sort(data.begin(), data.end(), comp);
// Get the lower bound
pair<double, double> low(make_pair(comp.target, 0.0));
vector< pair<double, double> >::iterator lower =
lower_bound(data.begin(), data.end(), low, comp);
// Get the upper bound
pair<double, double> up(make_pair(comp.target + 0.01, 0.0));
// N.B. use "lower_bound" here to get upper bound of target + 0.01 exclusive.
// If we want to include target + 0.01, use "upper_bound"
vector< pair<double, double> >::iterator upper =
lower_bound(data.begin(), data.end(), up, comp);
for_each(lower, upper, [](const pair<double, double> &data_point) {
cout << data_point.first << "\t" << data_point.second << "\n";
});
0.2 0.1
0.205 0.1
0.205 0
0.206 12.1
0.192 3.1
0.21 -12.9