我有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());
}
答案 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亿个元素,因此无论如何都会花费大量时间。至少几小时,如果不是几天。
其他想法是:
答案 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;
}