消除std :: vector中的重复项

时间:2012-04-10 12:13:21

标签: c++ algorithm stdvector

我有一个非常大的std :: vector std :: vectors,它包含固定数量的无符号整数。

所有uints向量都按升序排序。

我目前消除重复载体的方法是

unsigned int i = 0;
while ( i < new_combs.size() )
{
  unsigned int j = i + 1;
  while ( j < new_combs.size() )
  {
     unsigned int k = 0;
     while ( k < new_combs.at(i).size() && new_combs.at(i).at(k) == new_combs.at(j).at(k) )
        ++k;
     if ( k == new_combs.at(j).size() )
        new_combs.erase(new_combs.begin() + j);
     else
        ++j;
  }
  ++i;
}

这里,new_combs是一个包含上述向量的向量。

如果向量矢量未排序,是否有更有效的方法来消除重复?

6 个答案:

答案 0 :(得分:9)

较短的方法是使用<algorithm>

std::sort(new_combs.begin(), new_combs.end());
new_combs.erase(std::unique(new_combs.begin(), new_combs.end()), new_combs.end());

除非您特别需要std::vector,否则您可以使用std::set来避免重复。

答案 1 :(得分:3)

你考虑过使用std :: set吗?它是有序的,不允许重复开始。

答案 2 :(得分:2)

如果矢量未排序,您可以做的不多。如果它已排序,您可以使用算法中定义的unique方法:

new_combs.erase(unique(new_combs.begin(), new_combs.end()), new_combs.end());

答案 3 :(得分:0)

您的代码中有几个元素可以响起性能。

首先,您正在使用向量。从向量中删除元素总是很慢。 您可以考虑使用不同的容器(std :: list)或调整代码,以便您没有任何特殊值(例如零或-1)。

其次,您可以使用std :: set或std :: unordered_set来保留已经遇到的值。 这样,你只需要遍历你的矢量一次。

编辑:忘记这个答案了。我误读了这个问题,并认为必须删除重复的值(不是重复的向量)。

尽管如此,对评论给出了一些反应:

  • @Jerry:我同意矢量在大多数情况下比列表更快,但仅限于矢量的大小有限。如果向量包含100万个元素,你需要删除第3个,然后是第5个,然后是第10个,...你最终会移动很多元素。在这种情况下,列表可能会更快。
  • @James:在原始问题中,元素没有从向量的末尾删除,而是在中间。如果向量非常大(假设有100万个元素),那么删除元素仍然可能成为瓶颈。但是,我同意使用排序,其次是唯一可能更快。

答案 4 :(得分:0)

渐近地,您的算法看起来像通常的O(n)实现,因此是最佳的。 (尽管我不理解你使用ij的对角化策略,以及为什么你只删除,但从不移动元素。你的代码非常不清楚。) 但是,您正在复制STL,并且唯一环路的较短版本是:

struct unique {
    template <class C>
    void operator()( C& c ) {
         c.erase( std::unique( c.begin(), c.end() ), c.end() );
    }
};

std::for_each( new_combs.begin(), new_combs.end(), unique() );

答案 5 :(得分:0)

我同意Luchian Grigore's answer,但您也可以考虑将整个外部vector转换为unordered_set,这是一个O(n)操作,提供的子矢量哈希值也不大不平衡(与排序的平均O(n * log(n))相反)。您甚至可以将指针用于unordered_set中的子向量,以避免不必要的复制。对于大量数据而言,这可能是一个重要的性能差异。

This example说明了使用自己的哈希函数和指针的基本概念(它处理vector的{​​{1}}并使用string,而不是unordered_map ,但你应该能够很容易地根据你的需要修改它。)