使用[]运算符有效地使用C ++ unordered_map

时间:2011-08-01 11:27:37

标签: c++ unordered-map

首先,有人可以澄清在C ++中是否使用[]运算符和unordered_map进行查找包装调用find()方法,或者使用[]运算符比find()更快?

其次,在下面的一段代码中,我怀疑在unordered_map中尚未存在键的情况下,我通过行map[key] = value执行第二次查找以替换在那里创建的默认值当一个键不存在时使用[]运算符。

这是真的,如果是这样的话(可能通过使用指针或其他东西)我可能只会在任何情况下执行一次查找(可能通过存储放置值的位置/读取值的地址)来自)仍然实现相同的功能?显然,如果是这样,这将是一项有用的效率提升。

以下是修改后的代码摘录:

    int stored_val = map[key]; // first look up. Does this wrap ->find()??

    // return the corresponding value if we find the key in the map - ie != 0
    if (stored_val) return stored_val;

    // if not in map
    map[key] = value; 
       /* second (unnecessary?) look up here to find position for newly 
          added key entry */

   return value;

3 个答案:

答案 0 :(得分:44)

operator[]将为您输入一个带有默认构造值的条目(如果尚未存在)。它相当于,但可能会比以下更有效地实施:

iterator iter = map.find(key);

if(iter == map.end())
{
    iter = map.insert(value_type(key, int())).first;
}

return *iter;

operator[]可以比使用find()insert()手动完成工作更快,因为它可以节省重新哈希密钥。

在代码中进行多次查找的一种方法是引用值:

int &stored_val = map[key];

// return the corresponding value if we find the key in the map - ie != 0
if (stored_val) return stored_val;

// if not in map
stored_val = value;

return value;

请注意,如果地图中不存在该值,operator[]将默认构造并插入一个。因此,虽然这样可以避免多次查找,但如果使用default-construct + assign的类型比使用copy-或move-construct慢的类型,它实际上可能会更慢。

虽然使用int,哪个便宜默认构造为0,但您可以将0视为幻数,意味着为空。这看起来像你的例子中的情况。

如果你没有这样神奇的数字,你有两个选择。你应该使用什么取决于你计算价值的成本。

首先,当散列密钥很便宜但计算价值昂贵时,find()可能是最佳选择。这将散列两次,但只在需要时计算值:

iterator iter = map.find(key);

// return the corresponding value if we find the key in the map
if(iter != map.end()) return *iter;

// if not in map
map.insert(value_type(key, value));

return value;

但是如果你已经拥有了这个价值,那么你可以非常有效地做到这一点 - 也许比使用上面的参考+幻数更有效:

pair<iterator,bool> iter = map.insert(value_type(key, value));
return *iter.first;

如果map.insert(value_type)返回的bool为true,则插入该项。否则,它已经存在并且没有进行任何修改。迭代器返回指向映射中的插入值或现有值。对于您的简单示例,这可能是最佳选择。

答案 1 :(得分:10)

你们都可以检查一个元素是否存在,插入一个新元素(如果它不存在),使用特殊的insert函数返回一个pair<iterator, bool>,其中boolean值告诉您该值是否已实际插入。例如,代码here

  unordered_map<char, int> mymap;
  pair<unordered_map<char,int>::iterator,bool> ret;

  // first insert function version (single parameter):;
  mymap.insert ( pair<char,int>('z',200) );
  ret=mymap.insert (pair<char,int>('z',500) ); 
  if (ret.second==false)
  {
    cout << "element 'z' already existed";
    cout << " with a value of " << ret.first->second << endl;
  }

此处的代码会将对<'z',200>插入到地图中(如果它不存在)。如果返回的对的第二个元素的值为true,则返回插入它的迭代器,或者,如果该对的第二个元素为false,则返回元素实际所在的迭代器。

答案 2 :(得分:2)

  

首先,有人可以澄清在C ++中是否使用[]运算符和unordered_map进行查找包装调用Find()方法,或者使用[]运算符比Find()更快?

没有规则。 []的实现可以使用find(),它可以自己执行查找,也可以将查找委托给内部find()也使用的某个私有方法。

也无法保证哪一个更快。 find()涉及构造和返回迭代器的开销,而[]如果密钥不存在则可能会更慢,因为在这种情况下它会插入一个新值。

  

(...)是否有一种方法(可能通过使用指针或其他东西),我可能只会在任何情况下执行一次查找(...)

如果密钥不在地图中,[]将插入新的默认构造值,并返回引用。因此,您可以存储该引用以保存第二个查找:

int& stored_val = map[key];  // Note the reference

if (stored_val) return stored_val;

// Use the reference to save a second lookup.
stored_val = value; 

return value;