【问题标题】:Best way to merge multiple STL containers, removing duplicate elements?合并多个 STL 容器、删除重复元素的最佳方法?
【发布时间】: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 或更多)。

标签: c++ stl


【解决方案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。

    【讨论】:

      猜你喜欢
      • 2010-09-26
      • 1970-01-01
      • 2015-11-02
      • 2013-05-03
      • 2019-09-01
      • 1970-01-01
      • 2011-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多