我需要采取一个c++向量与潜在的很多元素,擦除重复,并排序。

我目前有下面的代码,但它不起作用。

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

我怎样才能正确地做到这一点呢?

此外,是先删除副本(类似于上面的编码)还是先执行排序更快?如果我先执行排序,它是否保证在std::unique执行后保持排序?

或者是否有另一种(也许更有效的)方法来完成这一切?


当前回答

更多可理解的代码来自:https://en.cppreference.com/w/cpp/algorithm/unique

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <cctype>

int main() 
{
    // remove duplicate elements
    std::vector<int> v{1,2,3,1,2,3,3,4,5,4,5,6,7};
    std::sort(v.begin(), v.end()); // 1 1 2 2 3 3 3 4 4 5 5 6 7 
    auto last = std::unique(v.begin(), v.end());
    // v now holds {1 2 3 4 5 6 7 x x x x x x}, where 'x' is indeterminate
    v.erase(last, v.end()); 
    for (int i : v)
      std::cout << i << " ";
    std::cout << "\n";
}

增长:

1 2 3 4 5 6 7

其他回答

关于alexK7基准测试。我尝试了它们,得到了类似的结果,但是当值的范围为100万时,使用std::sort (f1)和使用std::unordered_set (f5)的情况产生类似的时间。当取值范围为1000万时,f1比f5快。

如果值的范围是有限的,并且值是无符号int,则可以使用std::vector,其大小对应于给定的范围。代码如下:

void DeleteDuplicates_vector_bool(std::vector<unsigned>& v, unsigned range_size)
{
    std::vector<bool> v1(range_size);
    for (auto& x: v)
    {
       v1[x] = true;    
    }
    v.clear();

    unsigned count = 0;
    for (auto& x: v1)
    {
        if (x)
        {
            v.push_back(count);
        }
        ++count;
    }
}

大部分答案似乎是使用O(nlogn),但使用unordered_set,我们可以将其减少到O(n)。我看到了一些使用集合的解决方案,但我发现了这个解决方案,使用集合和迭代器似乎更优雅。

using Intvec = std::vector<int>;

void remove(Intvec &v) {
    // creating iterator starting with beginning of the vector 
    Intvec::iterator itr = v.begin();
    std::unordered_set<int> s;
    // loops from the beginning to the end of the list 
    for (auto curr = v.begin(); curr != v.end(); ++curr) {
        if (s.insert(*curr).second) { // if the 0 curr already exist in the set
            *itr++ = *curr; // adding a position to the iterator 
        }
    }
    // erasing repeating positions in the set 
    v.erase(itr, v.end());
}

unique只删除重复的元素,如果它们是邻居:你必须先对向量排序,然后它才能像你想的那样工作。

unique被定义为稳定的,所以在vector上运行unique之后,它仍然会被排序。

我不知道你在用这个干什么,所以我不能100%肯定地说,但通常当我想到“排序的,唯一的”容器时,我想到std::set。它可能更适合你的用例:

std::set<Foo> foos(vec.begin(), vec.end()); // both sorted & unique already

否则,在调用unique之前进行排序(正如其他答案所指出的那样)才是正确的方法。

如果你的类很容易转换为int型,并且你有一些内存, Unique可以在没有排序的情况下完成,而且速度快得多:

#include <vector>
#include <stdlib.h>
#include <algorithm>
int main (int argc, char* argv []) {
  //vector init
  std::vector<int> v (1000000, 0);
  std::for_each (v.begin (), v.end (), [] (int& s) {s = rand () %1000;});
  std::vector<int> v1 (v);
  int beg (0), end (0), duration (0);
  beg = clock ();
  {
    std::sort (v.begin (), v.end ());
    auto i (v.begin ());
    i = std::unique (v.begin (), v.end ());
    if (i != v.end ()) v.erase (i, v.end ());
  }
  end = clock ();
  duration = (int) (end - beg);
  std::cout << "\tduration sort + unique == " << duration << std::endl;

  int n (0);
  duration = 0;
  beg = clock ();
  std::for_each (v1.begin (), v1.end (), [&n] (const int& s) {if (s >= n) n = s+1;});
  std::vector<int> tab (n, 0);
  {
    auto i (v1.begin ());
    std::for_each (v1.begin (), v1.end (), [&i, &tab] (const int& s) {
      if (!tab [s]) {
        *i++ = s;
        ++tab [s];
      }
    });
    std::sort (v1.begin (), i);
    v1.erase (i, v1.end ());
  }
  end = clock ();
  duration = (int) (end - beg);
  std::cout << "\tduration unique + sort == " << duration << std::endl;
  if (v == v1) {
    std::cout << "and results are same" << std::endl;
  }
  else {
    std::cout << "but result differs" << std::endl;
  }  
}

典型结果: Duration sort + unique == 38985 持续时间唯一+排序== 2500 结果是一样的