有两个未排序的int向量和一个pair int,int的向量。
std::vector <int> v1;
std::vector <std::pair<int, float> > v2;
包含数百万个项目。
如何尽快从v1中删除那些独特于v2.first的项目(即未包含在v2.first中)?
例如:
v1: 5 3 2 4 7 8
v2: {2,8} {7,10} {5,0} {8,9}
----------------------------
v1: 3 4
有两个未排序的int向量和一个pair int,int的向量。
std::vector <int> v1;
std::vector <std::pair<int, float> > v2;
包含数百万个项目。
如何尽快从v1中删除那些独特于v2.first的项目(即未包含在v2.first中)?
例如:
v1: 5 3 2 4 7 8
v2: {2,8} {7,10} {5,0} {8,9}
----------------------------
v1: 3 4
使用某种关联容器(可能是 std::unordered_set
)来存储第二个向量中的所有整数,以使查找第一个向量中应删除的整数变得更加高效。
优化从初始向量中删除元素的方式。
std::unordered_set
并添加所有来自第二个向量的整数对中的第一个整数。这样可以 (期望的) 获得 O(1) 的查找时间,以检查特定的 int
是否存在于集合中。std::remove_if
算法从原始 vector
中删除存在于哈希表中的所有内容。你可以使用 Lambda 表达式来实现这一点:std::unordered_set<int> toRemove = /* ... */
v1.erase(std::remove_if(v1.begin(), v1.end(), [&toRemove] (int x) -> bool {
return toRemove.find(x) != toRemove.end();
}, v1.end());
unordered_set
中,预期时间复杂度为O(n)。第二步通过把所有删除操作集中到最后,使查找操作变得更加容易,预期总共需要O(n)的时间。整个过程的时间和空间复杂度都是O(n)。std::binary_search
检查第一个向量中的特定int
是否应该被删除。每次二分查找的时间复杂度为O(log n),所以总体时间复杂度为O(nlog n):排序的时间复杂度为O(nlog n),第一个向量中每个元素的时间复杂度为O(log n)(总计O(nlog n)),然后再花费O(n)的时间进行删除操作。假设两个容器都没有排序,而且排序实际上太昂贵或内存不足:
v1.erase(std::remove_if(v1.begin(), v1.end(),
[&v2](int i) {
return std::find_if(v2.begin(), v2.end(),
[](const std::pair<int, float>& p) {
return p.first == i; })
!= v2.end() }), v1.end());
或者对v2
按first
进行排序,然后使用二分搜索。如果有足够的内存,可以使用unordered_set
来对v2
的first
进行排序。
C++03完整版本:
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
struct find_func {
find_func(int i) : i(i) {}
int i;
bool operator()(const std::pair<int, float>& p) {
return p.first == i;
}
};
struct remove_func {
remove_func(std::vector< std::pair<int, float> >* v2)
: v2(v2) {}
std::vector< std::pair<int, float> >* v2;
bool operator()(int i) {
return std::find_if(v2->begin(), v2->end(), find_func(i)) != v2->end();
}
};
int main()
{
// c++11 here
std::vector<int> v1 = {5, 3, 2, 4, 7, 8};
std::vector< std::pair<int, float> > v2 = {{2,8}, {7,10}, {5,0}, {8,9}};
v1.erase(std::remove_if(v1.begin(), v1.end(), remove_func(&v2)), v1.end());
// and here
for(auto x : v1) {
std::cout << x << std::endl;
}
return 0;
}