簡體   English   中英

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

[英]Nested unordered_map / hash_map update in C++

我是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來說似乎可行,這意味着用鍵0更新了h1中的值(增加了1)。 盡管這看起來很瑣碎,但對於h3,我隨機插入了一些“對”(第一對,第二對)並使用哈希映射進行計數,但該計數似乎無法更新。 例如,可能是這樣的:

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中這永遠不會發生。 那么這個問題在哪里呢?

問題在這里:

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

這樣會導致整個子圖被復制到新的本地submap對象中。 當您離開示波器時銷毀它時,您對其所做的所有修改都會丟失。

相反,您可以使用對要修改的實際hashmap元素的引用:

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

這個&應該解決所有問題。

這是代碼第二部分的重構版本(我認為)。 我還在生成一致的測試數據集,以便我們可以在每次運行時重現行為(隨機性是測試的厭惡之物)。

這是代碼。 問題是什么?

#include <unordered_map>
#include <iostream>

using i2i = std::unordered_map<int, int>;
using map_i_to_i2i = std::unordered_map<int, i2i>;

void test_insert(map_i_to_i2i& outer, int v1, int v2)
{
    auto iouter = outer.find(v1);
    if (iouter == outer.end()) {
        std::cout << "case c) [" << v1 << "] = [" << v2 << "] = 1\n";
        outer[v1][v2] = 1;
    }
    else {
        auto& inner = iouter->second;
        auto iinner = inner.find(v2);
        if (iinner == inner.end())
        {
            std::cout << "case b) [" << v1 << "][" << v2 << "] = 1\n";
            inner.emplace_hint(iinner, v2, 1);
        }
        else {
            std::cout << "case c) [" << v1 << "][" << v2 << "] += 1\n";
            iinner->second += 1;
        }
    }
}

int main()
{
    map_i_to_i2i h3;
    for (int passes = 0 ; passes < 3 ; ++passes)
    {
        for (int x = 0 ; x < 2 ; ++x) {
            for (int y = 0 ; y < 2 ; ++y) {
                test_insert(h3, x, y);
            }
        }
    }
    return 0;
}

並不是真正的答案,只是一個供參考:如果這不僅僅是使用迭代器的練習,那么還有一種更簡單的方法:

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[]將默認構造並插入它。 對於地圖,這是一個空地圖,對於整數,它是零。

如果您想要另一個默認值,則可以使用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>

在這里,布爾值會告訴您是否插入了值,並且迭代器本身是std::pair<key,val>*的包裝,因此使用.first->second值。

除了更短/更易讀之外,這兩種方式都更加有效。 在您的代碼中,如果不存在該值,您將進行兩次查找,但是以上兩種方法均只進行一次查找。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM