合并多个 STL 容器、删除重复元素的最佳方法?

Posted

技术标签:

【中文标题】合并多个 STL 容器、删除重复元素的最佳方法?【英文标题】:Best way to merge multiple STL containers, removing duplicate elements? 【发布时间】:2008-11-11 15:52:29 【问题描述】:

我有两个要合并的 STL 容器,删除任何出现多次的元素。例如:

typedef std::list<int> container;
container c1;
container c2;

c1.push_back(1);
c1.push_back(2);
c1.push_back(3);

c2.push_back(2);
c2.push_back(3);
c2.push_back(4);

container c3 = unique_merge(c1, c2);
// c3 now contains the following 4 elements:
//   1, 2, 3, 4

std::unique 似乎仅适用于相邻元素,在我的情况下,容器可以按任何顺序排列。我猜我可以做一些 std::set 诡计:

container unique_merge(const container& c1, const container& c2)

    std::set<container::value_type> s;
    BOOST_FOREACH(const container::value_type& val, c1)
        s.insert(val);
    BOOST_FOREACH(const container::value_type& val, c2)
        s.insert(val);
    return container(s.begin(), s.end());

有没有更好的方法,还是我错过了明显出血的地方?

【问题讨论】:

如果你要求一些“明显流血”的东西,你的实现对于大多数情况来说已经足够好了。但是确实存在更好的算法,代价是 O(N * log(M)),其中 N 是所有容器中元素的总数,M 是容器的数量。代码不小,以后有时间再写。 @RnMss 真的吗?您可以发布答案吗? ... @user202729 天哪,那是 2014 年... @user202729 现在我不确定了。我认为...,根据我写的内容判断,...也许...当时我认为每个容器都已经排序,但容器的数量可能更大(比如 1000 或更多)。 【参考方案1】:

对于无序列表,你的设置技巧可能是最好的之一。每个插入应该是 O(log n),需要 N 个插入,遍历将是 O(n),给你 O(N*log n)。 另一种选择是在每个列表上单独运行 std::sort,然后使用std::set_union 并行遍历它们,这将为您删除重复项。这也将是 O(n*log n),因此如果您担心性能,则必须进行分析。如果不是,请选择对您更有意义的方法。

编辑: set_union 仅在原始列表中没有重复项时才有效,否则您将不得不使用 sortmergeuniqueerase。大 O 性能仍然相同,但对分析有相同的注意事项。

template <typename container>
container unique_merge(container c1, container c2)

    std::sort(c1.begin(), c1.end());
    std::sort(c2.begin(), c2.end());
    container mergeTarget;
    std::merge(c1.begin(), c1.end(), c2.begin(), c2.end(), 
        std::insert_iterator(mergeTarget, mergeTarget.end())
    );
    std::erase(
        std::unique(mergeTarget.begin(), mergeTarget.end()), 
        mergeTarget.end()
    );

    return mergeTarget;

【讨论】:

根据std::set_union的规范:如果在R1和R2这两个范围内有重复的元素,说V在R1中出现N次,在R2中出现M次,std的结果: :set_union 将包含 V 的 max(N, M) 个实例。因此,除非 N 这就是我没有测试编译它的结果。【参考方案2】:

您将需要排序(显式地,或通过像 set 这样的排序容器隐式地排序)。

有一个常见的习惯用法是使用 std::sort/std::unique/std::erase 来获取容器中的唯一元素。

所以创建一个包含 c1 内容的容器,附加 c2 的内容,然后排序,将唯一元素移到末尾,然后删除它们。像这样的:

container c(c1.begin(), c1.end());
c.insert(c.end(), c2.begin(), c2.end());
c.erase(std::unique(c.begin(), c.end()), c.end());

【讨论】:

【参考方案3】:

使用 STL 中的 std::set_union algorithm。不过,您需要先对输入列表进行排序——或者创建输入列表的副本,对其进行排序,然后使用 std::set_union。

【讨论】:

以上是关于合并多个 STL 容器、删除重复元素的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章

怎么删除STL容器的元素

在迭代时从地图(或任何其他STL容器)中删除/删除内容

仅通过迭代器删除 STL 容器元素

STL容器 -- Set

什么 STL 容器执行删除其间的元素?

STL—— 容器(vector)元素的删除