我正在尝试优化std::vector
“搜索” - 基于索引迭代向量并返回与“搜索”条件匹配的元素
struct myObj {
int id;
char* value;
};
std::vector<myObj> myObjList;
使用唯一的id
和值创建几千个条目,并将它们推送到向量myObjList
。
检索与myObj
匹配的id
的最有效方法是什么?
目前我的索引迭代如下:
for(int i = 0; i < myObjList.size(); i++){
if(myObjList.at(i).id == searchCriteria){
return myObjList.at(i);
}
}
注意:searchCriteria = int
。所有元素都有唯一的id
。
上面做的工作,但可能不是最有效的方式。
答案 0 :(得分:17)
C ++标准库有一些抽象算法,它给C ++一种功能性风格,正如我所说的那样,它让你更专注于搜索的标准,而不是你如何实现搜索自己。这适用于许多其他算法。
您正在寻找的算法是std::find_if
,通过迭代器范围进行简单的线性搜索。
在C ++ 11中,您可以使用lambda来表达您的标准:
std::find_if(myObjList.begin(), myObjList.end(), [&](const myObj & o) {
return o.id == searchCriteria;
});
如果没有C ++ 11可用,则必须提供谓词(函数对象(=函子)或函数指针),如果提供的实例是您要查找的实例,则返回true。 Functors的优势在于它们可以参数化,在您的情况下,您希望使用您要查找的ID参数化仿函数。
template<class TargetClass>
class HasId {
int _id;
public:
HasId(int id) : _id(id) {}
bool operator()(const TargetClass & o) const {
return o.id == _id;
}
}
std::find_if(myObjList.begin(), myObjList.end(), HasId<myObj>(searchCriteria));
此方法返回一个迭代器,指向找到的符合条件的第一个元素。如果没有这样的元素,则返回结束迭代器(指向矢量的末尾,而不是最后一个元素)。所以你的功能可能如下所示:
vector<myObj>::iterator it = std::find_if(...);
if(it == myObjList.end())
// handle error in any way
else
return *it;
答案 1 :(得分:11)
使用std::find_if
。
引用页面上有一个例子。
这是一个更准确地适合您的问题的工作示例:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct myObj
{
int id;
char* value;
myObj(int id_) : id(id_), value(0) {}
};
struct obj_finder
{
obj_finder(int key) : key_(key)
{}
bool operator()(const myObj& o) const
{
return key_ == o.id;
}
const int key_;
};
int main () {
vector<myObj> myvector;
vector<myObj>::iterator it;
myvector.push_back(myObj(30));
myvector.push_back(myObj(50));
myvector.push_back(myObj(100));
myvector.push_back(myObj(32));
it = find_if (myvector.begin(), myvector.end(), obj_finder(100));
cout << "I found " << it->id << endl;
return 0;
}
而且,如果你有C ++ 11可用,你可以使用lambda使这更简洁:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct myObj
{
int id;
char* value;
myObj(int id_) : id(id_), value(0) {}
};
int main ()
{
vector<myObj> myvector;
vector<myObj>::iterator it;
myvector.push_back(myObj(30));
myvector.push_back(myObj(50));
myvector.push_back(myObj(100));
myvector.push_back(myObj(32));
int key = 100;
it = find_if (myvector.begin(), myvector.end(), [key] (const myObj& o) -> bool {return o.id == key;});
cout << "I found " << it->id << endl;
return 0;
}
答案 2 :(得分:3)
这不是你问题的真正答案。其他回答的人给出了很好的答案,所以我没有什么可以补充的。
我想说的是你的代码不是非常惯用的C ++。当然,真正惯用的C ++会使用::std::find_if
。但即使您没有::std::find_if
,您的代码仍然不是惯用语。我将提供两次重写。一个是C ++ 11重写,第二个是C ++ 03重写。
首先,C ++ 11:
for (auto &i: myObjList){
if(i.id == searchCriteria){
return i;
}
}
其次,C ++ 03:
for (::std::vector<myObj>::iterator i = myObjList.begin(); i != myObjList.end(); ++i){
if(i->id == searchCriteria){
return *i;
}
}
通过任何类型的C ++容器的标准方法是使用迭代器。矢量可以用整数索引很好。但是,如果你不必要地依赖这种行为,那么如果你以后应该改变数据结构就会让自己变得更难。
答案 3 :(得分:2)
如果对id进行了排序,则可以执行二进制搜索(stl中还有一个函数binary_search
)。如果它们没有什么会表现得更好,但你仍然可以使用stl以较短的方式编写代码(使用find_if
)。