在unordered_map中查找的性能

时间:2011-08-11 00:16:13

标签: c++ unordered-map

我知道这可能是一个愚蠢的问题,但我想确定并且我无法轻易找到这些信息。

无序地图中find()的性能特征是什么?它是否像普通查找一样快/几乎快?

std::string defaultrow = sprite.attribute("defaultrow").value();
auto rclassIt = Rows::NameRowMap.find(defaultrow);
if (rclassIt != Rows::NameRowMap.end())
    defRow = rclassIt->second;

VS

std::string defaultrow = sprite.attribute("defaultrow").value();
defRow = Rows::NameRowMap[defaultrow];

其中Rows::NameRowMap是将字符串索引映射到int的无序映射。

在我的情况下,我不确定钥匙是否会存在,所以第一个解决方案对我来说似乎更安全,但如果我能保证存在,那么第二种情况会更快(忽略额外的检查我'我在干嘛?如果是这样,为什么?如果重要,我正在使用1.46提升实施

3 个答案:

答案 0 :(得分:4)

operator[]很可能在内部使用findinsert。例如,IIRC就是Miscrosoft std::map实施的情况。

编辑: 我想说的是operator[]不是神奇的,它仍然必须首先进行查找。从我在Boost 1.46.0中看到的find和所述运算符内部使用find_iterator

通常最好使用find进行查找,因为您的代码将更具可重用性和可靠性(例如,您永远不会意外插入某些内容),尤其是在某种通用代码中。

答案 1 :(得分:3)

无序容器上的

findoperator[]是O(1)平均值,O(n)最坏情况 - 它取决于散列函数的质量。

答案 2 :(得分:1)

它们具有与O(1)相同的摊销复杂度,但是当找不到值时,运算符也会创建一个新元素。如果找到该值,则性能差异应该很小。我的提升有点旧 - 版本1.41,但希望无关紧要。这是代码:

// find
//
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::iterator_base
hash_table<H, P, A, G, K>::find(key_type const& k) const
{
    if(!this->size_) return this->end();

    bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
    node_ptr it = find_iterator(bucket, k);

    if (BOOST_UNORDERED_BORLAND_BOOL(it))
        return iterator_base(bucket, it);
    else
        return this->end();
}

// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
    BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::value_type&
hash_unique_table<H, P, A, K>::operator[](key_type const& k)
{
    typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;

    std::size_t hash_value = this->hash_function()(k);
    bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);

    if(!this->buckets_) {
        node_constructor a(*this);
        a.construct_pair(k, (mapped_type*) 0);
        return *this->emplace_empty_impl_with_node(a, 1);
    }

    node_ptr pos = this->find_iterator(bucket, k);

    if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
        return node::get_value(pos);
    }
    else {
        // Side effects only in this block.

        // Create the node before rehashing in case it throws an
        // exception (need strong safety in such a case).
        node_constructor a(*this);
        a.construct_pair(k, (mapped_type*) 0);

        // reserve has basic exception safety if the hash function
        // throws, strong otherwise.
        if(this->reserve_for_insert(this->size_ + 1))
            bucket = this->bucket_ptr_from_hash(hash_value);

        // Nothing after this point can throw.

        return node::get_value(add_node(a, bucket));
    }
}