如何在向量上进行二进制搜索以找到具有特定id的元素

how to do a binary search on a vector to find element with certain id?

本文关键字:元素 id 向量 搜索 二进制      更新时间:2023-10-16

我有一个排序的向量,现在我想从该向量中找到具有特定id的元素。std::binary_search只是告诉我元素是否存在,所以我使用std::lower_bound:

#include <vector>
#include <iostream>
#include <algorithm>
struct Foo {
int id; 
// ... more members ... //
Foo(int id) : id(id) {} 
};
bool compareById(const Foo& a,const Foo& b) { return a.id < b.id; }
int main(){
std::vector<Foo> vect;
vect.push_back(10);
vect.push_back(123);
vect.push_back(0);
std::sort(vect.begin(),vect.end(),compareById);
int id_to_find = 1;
std::vector<Foo>::iterator f = std::lower_bound(vect.begin(),vect.end(),Foo(id_to_find),compareById);
if (f != vect.end() && f->id == id_to_find) { std::cout << "FOUND"; }
}

这有点奏效,但我非常不喜欢这样的做法,即我必须创建一个Foo(id_to_find)来将其传递给std::lower_bound,然后我必须仔细检查我得到的元素是否真的是我想要的元素。

我想我可以使用find_if来避免创建多余的实例,但据我所知,find_if只是线性的,没有利用正在排序的向量。我有点惊讶,我找不到合适的算法来完成任务,我已经在考虑写自己的算法了。

做这件事的方法是什么

有几件事可以让你的生活更轻松。第一件事是比较器不需要对于第一和第二参数具有相同的参数。要求是第一个参数必须隐式转换为去引用迭代器,第二个参数需要隐式转换成传递给lower_bound的第三个参数的类型。

我们可以利用这一点,只需将int作为第二个参数,这样就不必构造Foo。这使我们能够制作类似compareFooById

bool compareFooById(const Foo& a,const int& b) { return a.id < b; }

然后我们现在可以像这样使用它:

std::vector<Foo>::iterator f = std::lower_bound(vect.begin(), vect.end(), id_to_find, compareFooById);

注意,我确实在这里添加了一个新函数。您将compareById用于std::sort,所以我不能直接更改它,因为这会中断对sort的调用

现在,就必须检查是否有有效的迭代器而言,您有几个选项。您可以编写一个包装函数,该函数引用迭代器进行填充,并在迭代器找到项时返回。看起来像

template<typename It, typename Value, typename Comp
bool my_binary_search(It begin, It end, Value val, Comp c, It& ret)
{
ret = std::lower_bound(begin, end, val, c);
return ret != end;
}

然后你把它叫做

std::vector<Foo>::iterator f;
if(my_binary_search(vect.begin(), vect.end(), id_to_find, compareFooById, f))
//do something with f.

另一种选择是,如果找不到该项,则引发异常。在我看来,这不是你想做的,除非找不到物品是一个真正的例外。