如何在C ++中将已排序的向量合并为单个向量

时间:2017-01-07 09:50:02

标签: c++ c++11 vector

我有10,000 vector<pair<unsigned,unsigned>>并且我想将它们合并到一个向量中,以便按字典顺序排序并且不包含重复项。为此,我编写了以下代码。但是,令我惊讶的是,下面的代码花了很多时间。有人可以建议我如何减少代码的运行时间?

using obj = pair<unsigned, unsigned>
vector< vector<obj> > vecOfVec;  // 10,000 vector<obj>, each sorted with size()=10M

vector<obj> result;

for(auto it=vecOfVec.begin(), l=vecOfVec.end(); it!=l; ++it)
{
  // append vectors
  result.insert(result.end(),it->begin(),it->end());   
  // sort result  
  std::sort(result.begin(), result.end());
  // remove duplicates from result   
  result.erase(std::unique(result.begin(), result.end()), result.end());      
}

3 个答案:

答案 0 :(得分:2)

我认为你应该使用vectOfVect中的向量进行排序的事实。

因此,检测单个向量前面的最小值push_back() result,并删除从匹配最小值的向量前面检测到的所有值(避免重复{ {1}})。

如果您可以删除result变量,请注意(警告:未经过测试的代码:仅提供一个想法)

vecOfVec

如果可以的话,我建议你将while ( vecOfVec.size() ) { // detect the minimal front value auto itc = vecOfVec.cbegin(); auto lc = vecOfVec.cend(); auto valMin = itc->front(); while ( ++itc != lc ) valMin = std::min(valMin, itc->front()); // push_back() the minimal front value in result result.push_back(valMin); for ( auto it = vecOfVec.begin() ; it != vecOfVec.end() ; ) { // remove all the front values equals to valMin (this remove the // duplicates from result) while ( (false == it->empty()) && (valMin == it->front()) ) it->erase(it->begin()); // when a vector is empty is removed it = ( it->empty() ? vecOfVec.erase(it) : ++it ); } } vecOfVec切换到允许从单个容器(堆栈?)前面有效删除的东西,以及有效删除单个容器(a列出?)。

答案 1 :(得分:1)

如果有很多重复项,你应该使用set而不是vector来获得结果,因为set是存储没有重复项的东西最自然的东西:

set< pair<unsigned,unsigned> > resultSet;
for (auto it=vecOfVec.begin(); it!=vecOfVec.end(); ++it)
    resultSet.insert(it->begin(), it->end());

如果你需要把它变成一个矢量,你可以写

vector< pair<unsigned,unsigned> > resultVec(resultSet.begin(), resultSet.end());

请注意,由于您的代码运行超过8000亿个元素,因此无论如何都会花费大量时间。至少几小时,如果不是几天。

其他想法是:

  • 递归合并矢量(10000 - &gt; 5000 - &gt; 2500 - &gt; ... - &gt; 1)
  • 合并10000个向量,将10000个迭代器存储在堆结构中

答案 2 :(得分:1)

您的代码存在的一个问题是过度使用std::sort。不幸的是,当遇到已排序的数组时,快速排序算法(通常是std :: sort使用的工作马)并不是特别快。

此外,您还没有利用您的初始向量已经排序的事实。当您不需要再次调用sort时,可以通过使用下一个值的堆来利用它。这可以编码如下(使用obj = int进行代码测试),但也许可以使其更简洁。

// represents the next unused entry in one vector<obj>
template<typename obj>
struct feed
{
  typename std::vector<obj>::const_iterator current, end;
  feed(std::vector<obj> const&v)
    : current(v.begin()), end(v.end()) {}
  friend bool operator> (feed const&l, feed const&r)
  { return *(l.current) >  *(r.current); }
};

// - returns the smallest element
// - set corresponding feeder to next and re-establish the heap
template<typename obj>
obj get_next(std::vector<feed<obj>>&heap)
{
  auto&f = heap[0];
  auto x = *(f.current++);
  if(f.current == f.end) {
    std::pop_heap(heap.begin(),heap.end(),std::greater<feed<obj>>{});
    heap.pop_back();
  } else
    std::make_heap(heap.begin(),heap.end(),std::greater<feed<obj>>{});
  return x;
}

template<typename obj>
std::vector<obj> merge(std::vector<std::vector<obj>>const&vecOfvec)
{
  // create min heap of feed<obj> and count total number of objects
  std::vector<feed<obj>> input;
  input.reserve(vecOfvec.size());
  size_t num_total = 0;
  for(auto const&v:vecOfvec)
    if(v.size()) {
      num_total += v.size();
      input.emplace_back(v);
    }
  std::make_heap(input.begin(),input.end(),std::greater<feed<obj>>{});
  // append values in ascending order, avoiding duplicates
  std::vector<obj> result;
  result.reserve(num_total);
  while(!input.empty()) {
    auto x = get_next(input);
    result.push_back(x);
    while(!input.empty() &&
          !(*(input[0].current) > x))  // remove duplicates
      get_next(input);
  }
  return result;
}