map的并集,用相同的键将对应的值相加

Union of map with adding up the corresponding values with the same key

本文关键字:map      更新时间:2023-10-16

我有两个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;
}

有更好的方法吗?

试试下面的

#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;
}

好吧。因为您使用的是std::map,所以遍历集合的顺序定义得很好(参见遍历std::map的顺序是否已知(并由标准保证)?)

这意味着您可以对输入映射进行相当简单的一次遍历迭代,而不必在其中任何一个中进行一次查找。我相信,推进一个普通的前向迭代器应该是0(1)步。

插入是有趣的…根据cppreference,可以给std::map::insert提供一个提示参数,使得插入

如果插入发生在提示之前的位置,则为平摊常数,否则为容器大小的对数。

现在,假设我没有完全糊涂,当我们按顺序插入元素时,我们总是在映射的最后插入。因此,提示总是a3.end()。在c++ 11之前,您可以保留最后一个insert操作的返回结果,该结果将是紧接在结束之前的元素,因此紧接在下一个要插入的元素之前,并将其用作提示。

快速示例代码,可能工作,也可能不工作,E&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方法。如果您要使用一个合适的分配器,它支持为您的新map实例预分配内存池,那么您可能会从系统中挤出更多的性能。

最终,除非您提供一些效率度量,否则任何答案的有用程度都是有限的;-)

相关文章:
  • 没有找到相关文章