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

时间:2008-11-11 15:52:29

标签: c++ stl

我想要合并两个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());
}

有没有更好的方法或者我错过了明显出血的东西?

3 个答案:

答案 0 :(得分:6)

对于无序列表,您的设置技巧可能是最好的。每个插入应该是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;
}

答案 1 :(得分:3)

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

答案 2 :(得分:3)

您将需要排序(显式或隐式地通过像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());