如何在C ++中应用两个列表之间的交集?

时间:2016-08-17 09:57:04

标签: c++ list

我是C ++ list 的新手。

我有两个列表:list1list2。我需要在这些列表之间获得共同的元素。我怎么能得到这个?

1 个答案:

答案 0 :(得分:7)

如果您首先对两个列表进行排序,则可以使用Here

示例:

#include <algorithm>
#include <iostream>
#include <list>

int main() {
    std::list<int> list1{2, 5, 7, 8, -3, 7};
    std::list<int> list2{9, 1, 6, 3, 5, 2, 11, 0};

    list1.sort();
    list2.sort();

    std::list<int> out;
    std::set_intersection(list1.begin(), list1.end(), list2.begin(), list2.end(),
                          std::back_inserter(out));

     for(auto k : out)
         std::cout << k << ' ';
}

输出:

2 5

修改

上述方法可能不会是最佳方法,主要是因为对 std::list 进行排序对CPU来说并不好......

对于空间的权衡,对于较大的数据集,下面的方法肯定会更快,因为我们只迭代每个列表一次,并且每次迭代完成的所有操作都不会超过{{1}摊销的复杂性

O(1)

我使用template<typename T> std::list<T> intersection_of(const std::list<T>& a, const std::list<T>& b){ std::list<T> rtn; std::unordered_multiset<T> st; std::for_each(a.begin(), a.end(), [&st](const T& k){ st.insert(k); }); std::for_each(b.begin(), b.end(), [&st, &rtn](const T& k){ auto iter = st.find(k); if(iter != st.end()){ rtn.push_back(k); st.erase(iter); } } ); return rtn; } 而不是std::unordered_multiset,因为它保留了两个列表中常见重复项的出现

我在随机生成的std::unordered_set 9000 s上为这两种方法运行std::set_intersection,结果是(越低越好):

int

使用Average timings for 100 runs: intersection_of: 8.16 ms sortAndIntersect: 18.38 ms 方法的分析:

  • 对大小为std::set_intersection列表1 进行排序为:N
  • 对大小为O(Nlog(N))列表2 进行排序为:M
  • 查找交叉点是:O(Mlog(M))
  • 总计:O(M + N) ...(一般化为对数)

假设O( Nlog(N) + Mlog(M) + M + N)M相等,我们可以将其概括为:N

但是如果我们使用上面发布的O(Nlog(N))方法:

  • 通过大小为intersection_of列表1 进行迭代,并添加到该集合为:N
  • 通过大小为O(N) + O(1) = O(N)列表2 进行迭代,检查 multiset ,添加到 M ,从中删除列表2 out = O(M) + O(1) + O(1) + O(1)
  • 总计:O(M) ...(概括为线性)

假设O(M + N)M相等,我们可以将其概括为:N