如何在C++中将排序的向量合并为单个向量
How to merge sorted vectors into a single vector in C++
>我有 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());
}
我认为你应该使用vectOfVect
中的向量被排序的事实。
因此,在单个向量上检测前面的最小值,将其push_back()
在result
中,并删除从与最小值匹配的向量前面检测到的所有值(避免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
从vector< vector<obj> >
切换到允许从单个容器(堆栈?)前面有效移除和有效移除单个容器(列表?)的东西。
如果有很多
重复项,你应该使用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 -> 5000 -> 2500 -> ... -> 1) 要合并 10000 个
- 向量,请将 10000 个迭代器存储在堆结构中
代码的一个问题是过度使用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;
}
相关文章:
- 将向量的 N 段合并到位C++
- 使用向量在 c++ 中合并排序实现
- 如何合并函数返回的向量?
- 数组为此合并排序函数提供了正确的输出,但向量给出了不正确的输出.出了什么问题?
- C++ 合并排序返回原始向量
- 如何修复错误:使用向量查找最小值和最大值进行合并排序
- C++ 使用向量实现合并排序
- 如何使用C++有效地合并排序与向量
- 使用 move::语义将大量向量合并为更大的向量
- 合并排序的合并操作无法使用 c++ 向量
- 如何在C 中合并两个向量
- 合并,分类和删除重复分类的向量和未分类的向量
- 使用STL算法合并2个向量
- 合并2个不同长度的向量并事先对它们进行排序,而无需排序函数
- 将函数两个向量合并为第三个向量
- 如何在C++中将排序的向量合并为单个向量
- 与C 中的向量合并
- 将两个排序向量合并到一个排序向量中
- 将子向量合并/展平为单个向量c++(将2d转换为1d)
- 将向量合并到现有向量中