Given an array v
(some STL container, e.g. std::vector< double >
) of generally unsorted data (say assert(std::is_same< typeof(v), V >::value);
). Over the elements of the array is defined comparison operator, say std::less
. You need to create an array with n
minimal elements (copies form v
), but the elements are not default constructible (or is expensive operation). How to do it by means of STL? Non-modifying sequence algorithm is required.
Originally seen as a way to solve using std::back_insert_iterator
, but there is some confusion as explained further:
assert(!std::is_default_constructible< typename V::value_type >::value); // assume
template< class V >
V min_n_elements(typename V::const_iterator begin, typename V::const_iterator end, typename V::size_type const n)
{
assert(!(std::distance(begin, end) < n));
V result; // V result(n); not allowed
result.reserve(n);
std::partial_sort_copy(begin, end, std::back_inserter(result), /*What should be here? mb something X(result.capacity())?*/, std::less< typename V::value_type >());
return result;
}
I want to find solution that is optimal in terms of time and memory (O(1) additional memory and <= O(std::partial_sort_copy
) time consumption). Totally algorithm should operate on the following number of memory: v.size()
elements of non-modifiable source v
as input and n
of newly created elements, all of which are copies of the n
smallest elements of source array v
, as output. That's all. I think this is a realistic limits.
EDIT: reimplemented with heap:
template< class V >
V min_n_elements(typename V::const_iterator b, typename V::const_iterator e, typename V::size_type const n) {
assert(std::distance(b, e) >= n);
V res(b, b+n);
make_heap(res.begin(), res.end());
for (auto i=b+n; i<e; ++i) {
if (*i < res.front()) {
pop_heap(res.begin(), res.end());
res.back() = *i;
push_heap(res.begin(), res.end());
}
}
return std::move(res);
}