地图联合用相同的键加上相应的值

时间:2014-05-11 13:11:13

标签: c++ map

我有两个std::map<char, int> A1, A2;,我想合并这两张地图。问题是,我如何编写最有效的代码来将值添加到两个地图中的相同键中?

例如:

A1: ('a', 10), ('c', 8), ('z', 7)
A2: ('c', 12), ('q', 9), ('s', 2), ('u', 8)

A3 = merge(A1, A2); // A3 should be: ('a', 10), ('c', 20), ('q', 9), ('s', 2), ('u', 8), ('z', 7)

更新:我能想到的是:

std::map<char, int>::iterator it;
for (it = A2.begin(); it != A2.end(); it++)
{
    A1[ it->first ] += it->second;
}

有没有更好的方法?

2 个答案:

答案 0 :(得分:0)

尝试以下

#include <iostream>
#include <map>

int main() 
{
    std::map<char, int> m1 = { { 'a', 10 }, { 'c', 8 }, { 'z', 7 } },
                        m2 = { { 'c', 12 }, { 'q', 9 }, { 's', 2 }, { 'u', 9 } };


    for ( const auto &p : m2 ) m1[p.first] += p.second;

    for ( const auto &p : m1 ) std::cout << p.first << '\t' << p.second << std::endl;

    return 0;
}

答案 1 :(得分:0)

好。因为您使用的是std::map,所以通过集合的迭代顺序得到了很好的定义(参见Is the order of iterating through std::map known (and guaranteed by the standard)?

这意味着您可以对输入映射执行相当简单的一次性迭代,而无需在其中任何一个中执行单个查找。推进正常的前向迭代器应该是O(1)步骤,我相信。

插入很有意思...根据cppreferece,你可以为std::map::insert提供一个提示参数,这会使插入

  

如果插入发生在提示之前的位置,则为分摊常数,否则为对数。

现在,假设我不是完全愚蠢,因为我们按顺序插入元素,我们总是插入地图的最后。因此,提示始终为a3.end()。在C ++ 11之前,您可以保留最后insert操作的返回结果,该操作将在结束之前的元素之前,因此紧接在插入的下一个元素之前,并将其用作您的提示

快速示例代码,可能有效也可能无效,E&amp; OE,YMMV等!

std::map<char, int> a1, a2, a3;
// populate a1 and a2 yourself here. elided for brevity.

auto a1i = a1.begin();
auto a2i = a2.begin();

while(a1i != a1.end() && a2i != a2.end())
{
    if (a1i->first < a2i->first)
    {
            a3.insert(a3.end(), *a1i);
            a1i++;
    }
    else if (a1i->first == a2i->first)
    {
            a3.insert(
                a3.end(),
                std::make_pair(a1i->first, a1i->second + a2i->second));
            a1i++;
            a2i++;
    }
    else if (a1i->first > a2i->first)
    {
            a3.insert(a3.end(), *a2i);
            a2i++;
    }

    continue;
}

// push remaining elements, if any, into a3.
// this is O(NlogN), but you should use hinted insert as above to make it O(N)
a3.insert(a1i, a1.end());
a3.insert(a2i, a2.end());

注意:与示例代码相比,这种方式避免了每次迭代的树查找,并且可以与不可变映射一起用作输入。与您的O(NlogN)相比,我的代码的最佳案例性能应为O(N)(已摊销,并假设我已正确使用insert提示)的顺序。上面的最终insert代码只是为了简洁而保留在效率较低的形式中。

现在,还有内存分配的可能问题。如果您的源映射中的任何一个(或两个)都非常大,那么如果您可以预先分配一块适合至少适合两个映射中较大的一个的内存块,那就太好了。但是,std::map没有reserve方法。如果您要使用一个合适的分配器来支持为新映射实例预先分配内存池,那么您可能会从系统中挤出更多的性能。

最终,除非您提供一些效率指标,否则任何答案的有用程度都会受到限制; - )