嵌套的unordered_map / hash_map在C ++中更新

时间:2017-03-19 08:11:55

标签: c++ hashmap unordered-map

我是C ++的新手,并且在unordered_map(或hash_map)方面存在以下问题:

#include <unordered_map>
#include <iostream>
using namespace std;

int main()
{
    unordered_map<int,int> h1;
    int temp1=0;
    h1.insert(pair<int,int>(0,temp1));
    unordered_map<int, unordered_map<int,int>> h2;
    h2.insert(pair<int, unordered_map<int,int>>(1,h1));
    unordered_map<int, unordered_map<int,int>>::iterator h2_itor=h2.find(1);
    h2_itor->second.find(0)->second++;

    unordered_map<int, unordered_map<int,int>> h3;
    for(int i=0;i<100;i++)
    {
        int first=rand()%10;
        int second=rand()%10;

        unordered_map<int, unordered_map<int,int>>::iterator h3_itor=h3.find(first);
        if(h3_itor!=h3.end())
        {
            unordered_map<int,int> submap=h3_itor->second;
            unordered_map<int,int>::iterator submap_itor=submap.find(second);
            if(submap_itor!=submap.end())
                submap_itor->second++;
            else
                submap.insert(pair<int,int>(second, 1));
        }
        else
        {
            unordered_map<int,int> submap;
            submap.insert(pair<int,int>(second,1));
            h3.insert(pair<int, unordered_map<int,int>>(first,submap));
        }
    }

    return 0;
}

输出很奇怪。对于h1和h2,似乎有效,这意味着更新了h1中带有键0的值(递增1)。虽然这看起来微不足道,但对于h3,我随机插入一些&#34;对&#34; (第一个,第二个)并使用哈希映射计数,计数似乎无法更新。例如,它可能是这样的:

insert 1 -> 7 -> 1 
 ... 
now update 1 -> 7 -> 1 to 1 -> 7 -> 2 using my code
fetch: h3.find(1)->second.find(7)->second : it's still 1 but not 2!

表示更新值不成功。我知道在Java中这种情况从未发生过。那么这个问题在哪里呢?

3 个答案:

答案 0 :(得分:1)

问题在于:

unordered_map<int,int> submap = h3_itor->second;

这会导致整个子图复制到您的新本地submap对象中。当你离开范围时,你所做的所有修改都会丢失。

相反,您可以使用对要修改的实际hashmap元素的引用:

unordered_map<int,int> &submap = h3_itor->second;

这一个&应该解决所有问题。

答案 1 :(得分:0)

这是代码第二部分的重构版本(我认为)。我也在生成一致的测试数据集,因此我们可以在每次运行时重现行为(随机性是测试的一种诅咒)。

这是代码。问题是什么?

set

答案 2 :(得分:0)

不是一个真正的答案,只是一个FYI:如果这不仅仅是使用迭代器的练习,那么有一个更简单的方法:

unordered_map<int, unordered_map<int,int>> h3
h3[0][0] = 1;

for (int i=0; i<100; i++ ) {
    int first=rand()%10;
    int second=rand()%10;
    h3[first][second]++;
}

这是有效的,因为如果缺少值,unordered_map::operator[]将默认构造并插入它。对于地图,这是一个空地图,对于一个int,它是零。

如果您想要其他默认设置,可以使用unordered_map::emplace,例如:

unordered_map<int, unordered_map<int,int>> h3
h3[0][0] = 2;

for (int i=0; i<100; i++ ) {
    int x=rand()%10;
    int y=rand()%10;
    int& val = h3[x].emplace(y, 1).first->second;
    val *= 2;
}

是的,这有点令人困惑:如果缺少密钥,emplace会插入指定的值(如果密钥已经存在则不会覆盖),并返回std::pair<iterator, bool>

这里,bool告诉你是否插入了你的值,迭代器本身是std::pair<key,val>*的包装器,因此.first->second得到了值。

除了更短/更易读之外,这两者也更有效。如果值不存在,则在代码中进行两次查找,但上述两种方法都只进行一次查找。