两个向量<mytype *> A和B </mytype *>之间的差异

时间:2010-06-28 18:53:11

标签: c++ set set-difference

我有两个名为vector<MyType*>A的{​​{1}}个对象。 MyType类有一个字段B,我希望得到IDMyType*而不是A中的B。我正在研究图像分析应用程序,我希望找到一个快速/优化的解决方案。

4 个答案:

答案 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矢量中预订。