简体   繁体   English

在 unordered_map 中查找的性能

[英]performance of find in an unordered_map

I know this is probably a stupid question, but I wanted to make sure and I couldn't readily find this information.我知道这可能是一个愚蠢的问题,但我想确定一下,但我无法轻易找到这些信息。

What is the performance characteristic of find() in an unordered map? find() 在无序 map 中的性能特征是什么? Is it as fast/nearly as fast as a normal lookup?它是否与正常查找一样快/几乎一样快?

Ie IE

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];

where Rows::NameRowMap is a unordered map mapping a string index to an int.其中Rows::NameRowMap是将字符串索引映射到 int 的无序 map。

In my case, I don't know for certain if the key will exist before hand, so the first solution seemed safer to me, but if I can guarantee existence, is the second case faster (ignoring the extra checks I'm doing)?就我而言,我不确定密钥是否会事先存在,所以第一个解决方案对我来说似乎更安全,但如果我能保证存在,第二种情况会更快(忽略我正在做的额外检查) ? and if so, why?如果是这样,为什么? If it matters, I'm using the 1.46 boost implementation如果重要的话,我正在使用 1.46 boost 实现

It's pretty possible that operator[] uses find and insert internally. operator[]很可能在内部使用findinsert For example, IIRC that's the case with Miscrosoft's std::map implementation.例如,IIRC 就是 Miscrosoft 的std::map实现的情况。

EDIT: What I was trying to say is that operator[] is not magical, it still has to do a lookup first.编辑:我想说的是operator[]并不神奇,它仍然需要先进行查找。 From what I see in Boost 1.46.0 both find and said operator use find_iterator internally.从我在 Boost 1.46.0 中看到的内容来看, find和 said 操作符都在内部使用find_iterator

Usually it's better to use find for lookups, because your code will be more reusable and robust (eg you will never insert something accidentally), especially in some kind of generic code.通常最好使用find进行查找,因为您的代码将更具可重用性和健壮性(例如,您永远不会意外插入某些内容),尤其是在某种通用代码中。

find and operator[] on an unordered container are O(1) average, O(n) worst-case -- it depends on the quality of your hash function.无序容器上的findoperator[]平均为 O(1),最坏情况为 O(n) - 这取决于您的 hash function 的质量。

They have the same amortized complexity of O(1), but the operator also creates a new element when the value is not found.它们具有相同的 O(1) 的摊销复杂度,但是当找不到值时,运算符也会创建一个新元素。 If the value is found, performance difference should be minor.如果找到该值,则性能差异应该很小。 My boost is a little old - version 1.41, but hopefully it does not matter.我的提升有点旧 - 版本 1.41,但希望没关系。 Here is the code:这是代码:

// 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));
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM