有几个项目可以通过密钥进行迭代和搜索。我已经为迭代形成了std::vector
。我是否需要为struct
之类的搜索形成std::unordered_map
?
我确实知道在std::vector
中搜索O(N)
并在std::unordered_map
中搜索导致O(1)
。但是里面的项目大约是10.初始化后没有插入或更新。我可能会搜索很多次。也许一百万,十亿甚至更多,我无法确定它。
我担心散列可能比迭代更昂贵。
以下是一个示例:
class Item
{
public:
int key;
const char* value;
};
class Items
{
public:
Items(const std::vector<const Item> items)
: _vector(items)
, _map(generateMap()){
}
const char* getValueByKey(int key) const {
//which one to choose
//map
// const auto& iter = _map.find(key);
// if (iter!=_map.end()) {
// return iter->second;
// }
// return nullptr;
//vector
for (const auto& iter : _vector) {
if (iter.key==key) {
return iter.value;
}
}
return nullptr;
}
protected:
const std::unordered_map<int, const char*> generateMap() const{
std::unordered_map<int, const char*> map;
for (const auto& item : _vector) {
map.insert({item.key, item.value});//I can make sure that no same key will exists
}
return map;
}
const std::vector<const Item> _vector;
const std::unordered_map<int, const char*> _map;//Is it necessary?
};
int main()
{
const std::vector<const Item> items ={
{1, "value_1"},
{20, "value_2"},
{10, "value_3"},
{55, "value_4"},
};
Items theItems = items;
srand(time(nullptr));
for (int i = 0; i < 1000000; i++) {
int key = rand();
printf("%d %s exists\n", key, theItems.getValueByKey(key)==nullptr?"is not":"is");
}
return 0;
}
这是一个int
密钥案例,可能没有发生散列。但是其他情况呢,std::string
,用户定义的struct
等等?
那么我应该如何在理论上对这种情况做出决定呢?
答案 0 :(得分:5)
政治上正确的答案是&#34;基准!&#34;。
但是根据其他人的经验,当只使用少量相对较小的项目时,使用std::vector
通常会更快(特别是如果它已经排序),因为它可以提高项目的内存位置和不为其项使用额外的堆分配/释放。但是,如果密钥类似于std::string
并且密钥比较是使用其内容完成的,那么这当然可能会损害内存局部性,因为字符串内容不是(总是)包含在字符串对象本身中,但是在堆上。
答案 1 :(得分:4)
如果您不打算更改数据并且需要进行多次搜索,我建议您尝试使用std:vector
和对其进行排序。然后,您可以使用查找算法,例如来自STL的 binary_search , lower_bound 或 upper_bound ,利用容器已排序的事实。
您获得最佳:地点和O(log(N))复杂性。
答案 2 :(得分:0)
对于少量项目,但查找大约十亿次,我们需要看看哪个更快,一个向量的短迭代与unordered_map,如上所述可以给你O(1)性能只要你避免碰撞。向量的单次迭代可能比地图的散列更快。那么问题就是地图变为平均查找速度更快的项目数。要确定答案,您应该在两者之间进行基准测试,以确定实际上为您的特定情况提供最佳时间。
或者,因为您提到初始化后不会发生插入或更新,如果您的密钥范围很小,您可以使用查找表,这将以最小的内存开销为代价提供最快的性能(无散列问题) 。
答案 3 :(得分:0)
我会看一下boost::flat_map
,它提供了一个矢量实现的地图界面。
无论Big O的复杂程度如何,事实上,由于数据的局部性和从主内存中预取数据,您的硬件使用矢量而不是地图会表现得更好。
引用Chandler Carruth,&#34;地图是减慢代码速度的练习&#34;