我有两个名为vector<MyType*>
和A
的{{1}}个对象。 MyType类有一个字段B
,我希望得到ID
中MyType*
而不是A
中的B
。我正在研究图像分析应用程序,我希望找到一个快速/优化的解决方案。
答案 0 :(得分:2)
根据ID对两个向量(std::sort
)进行排序,然后使用std::set_difference
。您需要定义一个自定义比较器以传递给这两种算法,例如
struct comp
{
bool operator()(MyType * lhs, MyType * rhs) const
{
return lhs->id < rhs->id;
}
};
答案 1 :(得分:2)
无序方法通常具有二次复杂度,除非事先对数据进行排序(通过您的ID字段),在这种情况下,它将是线性的,不需要通过B重复搜索。
struct CompareId
{
bool operator()(const MyType* a, const MyType* b) const
{
return a>ID < b->ID;
}
};
...
sort(A.begin(), A.end(), CompareId() );
sort(B.begin(), B.end(), CompareId() );
vector<MyType*> C;
set_difference(A.begin(), A.end(), B.begin(), B.end(), back_inserter(C) );
另一个解决方案是使用一个有序的容器,比如std :: set,其中CompareId用于StrictWeakOrdering模板参数。我认为如果你需要应用大量的设置操作会更好。这有自己的开销(作为一棵树),但如果你真的发现这是一个效率问题,你可以实现一个快速的内存分配器来超快地插入和删除元素(注意:只有这样做,如果你分析并确定这是瓶颈)。
警告:进入一些复杂的领域。
您可以考虑另一种解决方案,如果适用,可以非常快速,您永远不必担心排序数据。基本上,使任何共享相同ID的MyType对象组存储共享计数器(例如:指向unsigned int的指针)。
这将需要为计数器创建ID映射,并且每次根据其ID创建MyType对象时都需要从映射中提取计数器。由于您的MyType对象具有重复的ID,因此您不必像创建MyType对象那样经常插入地图(大多数可能只是获取现有的计数器)。
除此之外,还有一个全局“遍历”计数器,只要它被提取就会递增。
static unsigned int counter = 0;
unsigned int traversal_counter()
{
// make this atomic for multithreaded applications and
// needs to be modified to set all existing ID-associated
// counters to 0 on overflow (see below)
return ++counter;
}
现在让我们回到你有A和B向量存储MyType *的地方。要获取A中不在B中的元素,我们首先调用traversal_counter()。假设这是我们第一次调用它,那将给我们一个遍历值为1.
现在迭代B中的每个MyType *对象,并将每个对象的共享计数器从0设置为遍历值1。
现在遍历A中的每个MyType *对象。具有与当前遍历值(1)不匹配的计数器值的那些是A中未包含在B中的元素。
当您遍历遍历计数器时会发生什么?在这种情况下,我们遍历ID映射中存储的所有计数器,并将它们与遍历计数器本身一起设置为零。如果它是一个32位的无符号整数,这只需要在大约40亿次遍历中出现一次。
这是您可以应用于给定问题的最快解决方案。它可以在未排序的数据上以线性复杂度进行任何设置操作(并且总是,不仅仅是在散列表等最佳情况下),但它确实引入了一些复杂性,所以只有在你确实需要时才考虑它。
答案 2 :(得分:1)
首先看一下这个问题。你想要“A中的一切都不在B中”。这意味着你将不得不访问“A中的所有东西”。你还必须访问B中的所有内容,以了解B中的内容和内容。因此,这表明应该有一个O(n) + O(m)
解决方案,或者自由地忽略n和m之间的差异,{{ 1}}。
让我们考虑O(2n)
方法。每种排序均为std::set_difference
,set_difference为O(n log n)
。所以sort-sort-set_difference方法是O(n)
。我们称之为O(n + 2n log n)
。
另一种方法是首先将B的元素放在一个集合(或地图)中。跨B创建集合的迭代是O(4n)
加上每个元素的插入O(n)
,然后在AO(n)上迭代,查找A(log n)的每个元素,得到总数: O(log n)
。我们称之为O(2n log n)
,这稍微好一些。
最后,使用unordered_set(或unordered_map),假设我们得到O(3n)
插入和O(1)
查找的平均情况,我们的方法是O(1)
。 A-公顷!
这里真正的胜利是unordered_set(或map)可能是首先表示数据的最自然的选择,即正确的设计产生优化的实现。这并不总是会发生,但它确实很好!
答案 3 :(得分:0)
如果B预先存在于A,则在填充A时,您可以在C矢量中预订。