【问题标题】:STL structures: "insert if not present" operation?STL结构:“如果不存在则插入”操作?
【发布时间】:2015-10-06 15:33:07
【问题描述】:

我现在正在开发一个处理一些指数时间算法的程序。正因为如此,我的程序的一个主循环运行了很多次,我正在尝试尽可能优化它。

分析表明,大部分时间都花在了std::unordered_map 的查找和哈希计算上。

我想知道:

  1. 有没有办法缓存 std::unordered_map 的键的哈希值,然后将其作为参数提供以供以后插入?

  2. 有没有一种方法可以在单个操作中执行以下操作:给定一个键和值 {x,y},检查键 x 是否在映射中,如果不在,插入它并返回{x,y},否则返回{x,z},无论z已经在地图中。

我现在正在做这样的事情,但是效率很低,因为我必须计算键的哈希值并检查它是否在地图中。但如果它不在地图中,我会进行完全独立的插入操作。理论上,检查它是否存在于地图中应该会找到它在地图中插入的位置。

我愿意尝试其他数据结构,例如 std::map 或来自 Boost 的东西,如果它们可以减少此操作的时间。

【问题讨论】:

  • 改用线程。或者您可以使用 OpenMP 并行化您的循环
  • 密钥类型是什么?
  • 顺便说一句,你研究过插入提示吗?
  • 有一种插入函数形式,它接受一个提示——一个指向搜索开始位置的迭代器。如果你已经有一个职位,你可以试试这个。不过,这对于有序地图非常有用。
  • @NathanOliver,向量与列表比较与关联容器有什么关系????

标签: c++ optimization data-structures stl unordered-map


【解决方案1】:

你可以只使用std::unordered_map::insert()的返回值来实现key存在检查+单哈希计算插入。

template<typename K, typename V>
std::pair<K, V> myinsert(std::unordered_map<K, V> &map, const std::pair<K, V> &kv)
{
    return *(map.insert(kv).first);
}

【讨论】:

  • 旁注:还有std::map::emplace
  • 返回V 本身就足够了,因为密钥是已知的——它已被传递到函数中。
  • @DieterLücking 我建议更改返回值,而不是参数。 return (map.insert(kv).first)-&gt;second.
  • 这是否会用kv.second 中的任何内容覆盖先前与k 关联的值v
  • 没有。根据文档,现有的 kv 对被返回并保持原样。
【解决方案2】:

您不能缓存键的哈希值,但如果您有一个迭代器到它上次所在的位置(从您最初插入时开始,或者从您上次成功找到该项目时开始),您可以使用 @987654321 @ 成员,它还有助于将迭代器返回到新插入的元素或阻止插入的先前存在的元素。

【讨论】:

  • “上次在哪里”是什么意思?例如,我上次插入时的迭代器,或者我做find(x) 时的迭代器,它没有找到它?
【解决方案3】:

你可以使用std::map::emplace()

只有容器中没有其他元素具有与所放置的元素等效的键(地图容器中的键是唯一的)时才会发生插入。

例子

#include <iostream>
#include <utility>
#include <string>
#include <map>

typedef std::map<std::string, std::string> StringMap; 
typedef std::pair<StringMap::iterator, bool> PairKey;

int main()
{
    std::map<std::string, std::string> m;

    // uses pair's template constructor
    m.emplace("a", "aaa");
    m.emplace("b", "bbb");
    m.emplace("d", "ddd");

    PairKey pair = m.emplace("d", "dddddd");

    if (pair.second == false)
        std::cout<< "d was existed so value didn't change" << std::endl;
    
    std::cout<<"-------MAP_LIST------" << std::endl;
    for (const auto &p : m)
       std::cout << p.first << " => " << p.second << '\n';
    std::cout<<"-------========------" << std::endl;
}

输出:

d was existed so value didn't change
-------MAP_LIST------
a => aaa
b => bbb
d => ddd
-------========------

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-09-17
    • 2012-06-24
    • 2018-02-05
    • 2014-06-11
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 2016-05-15
    相关资源
    最近更新 更多