You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效提取两个std::unordered_map<std::string,std::set<A>>的增减元素?

更高效的unordered_map<string, set<A>>差异提取实现

你的代码能实现基本的差异提取,但存在两个可优化的点:一是对set的差异计算用了多次find操作,时间效率有提升空间;二是未处理t1中存在但t2中不存在的key——这些key对应的整个集合都属于被删除的内容。

下面是优化后的实现,核心利用set的有序性,通过双指针遍历替代多次find,把单组set的差异计算时间复杂度从O(n log n + m log m)降到O(n + m):

#include <iostream>
#include <string>
#include <unordered_map>
#include <set>
#include <algorithm>

struct A {
    std::string name;
    std::string address;

    auto operator<=>(const A& other) const = default;
};

using T = std::unordered_map<std::string, std::set<A>>;

void extractChanges(const T& t1, const T& t2, T& added, T& removed) {
    // 处理t2中的key:对比t1中同key的set差异
    for (const auto& [key, set_t2] : t2) {
        auto it_t1 = t1.find(key);
        if (it_t1 == t1.end()) {
            // t1中无此key,整个set_t2都是新增
            added.emplace(key, set_t2);
            continue;
        }

        const std::set<A>& set_t1 = it_t1->second;
        std::set<A> added_set, removed_set;

        // 双指针遍历两个有序set,找出差异
        auto it1 = set_t1.begin();
        auto it2 = set_t2.begin();
        while (it1 != set_t1.end() && it2 != set_t2.end()) {
            if (*it1 < *it2) {
                // 元素在t1不在t2,属于删除
                removed_set.insert(*it1);
                ++it1;
            } else if (*it2 < *it1) {
                // 元素在t2不在t1,属于新增
                added_set.insert(*it2);
                ++it2;
            } else {
                // 元素相同,跳过
                ++it1;
                ++it2;
            }
        }

        // 处理t1中剩余的元素(都是删除的)
        while (it1 != set_t1.end()) {
            removed_set.insert(*it1);
            ++it1;
        }

        // 处理t2中剩余的元素(都是新增的)
        while (it2 != set_t2.end()) {
            added_set.insert(*it2);
            ++it2;
        }

        if (!added_set.empty()) {
            added.emplace(key, std::move(added_set));
        }
        if (!removed_set.empty()) {
            removed.emplace(key, std::move(removed_set));
        }
    }

    // 处理t1中独有的key:整个set都是删除的
    for (const auto& [key, set_t1] : t1) {
        if (t2.find(key) == t2.end()) {
            removed.emplace(key, set_t1);
        }
    }
}

int main() {
    T t1 = {
        {"key1", {{"name1", "address1"}, {"name2", "address2"}}},
        {"key2", {{"name3", "address3"}}}
    };

    T t2 = {
        {"key1", {{"name1", "address1"}, {"name2", "address2_modified"}}},
        {"key3", {{"name4", "address4"}}}
    };

    T added, removed;
    extractChanges(t1, t2, added, removed);

    // 打印验证结果
    std::cout << "Added elements:\n";
    for (const auto& [k, s] : added) {
        std::cout << "Key: " << k << "\n";
        for (const auto& a : s) {
            std::cout << "  " << a.name << " - " << a.address << "\n";
        }
    }

    std::cout << "\nRemoved elements:\n";
    for (const auto& [k, s] : removed) {
        std::cout << "Key: " << k << "\n";
        for (const auto& a : s) {
            std::cout << "  " << a.name << " - " << a.address << "\n";
        }
    }

    return 0;
}

关键优化细节

  1. 双指针遍历有序集合:因为set是基于红黑树的有序容器,双指针可以线性遍历两个集合,一次遍历就能区分出新增、删除和相同元素,避免了原代码中每个元素O(log n)的find开销。
  2. 补全t1独有key的处理:原代码只处理了t2中存在的key,优化后的代码会遍历t1的所有key,把t2中没有的key对应的整个集合加入removed,逻辑更完整。
  3. 移动语义减少拷贝:对临时构建的added_set和removed_set使用std::move转移所有权,避免不必要的集合拷贝操作。

内容的提问来源于stack exchange,提问作者Peter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 20:42:31