std :: vector和std :: unordered_map之间的选择用于搜索少数项目案例?

时间:2017-02-09 08:06:50

标签: c++ algorithm performance c++11 stl

有几个项目可以通过密钥进行迭代和搜索。我已经为迭代形成了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等等?

那么我应该如何在理论上对这种情况做出决定呢?

4 个答案:

答案 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;