问题
I have a strong use-case to define my own sorting algorithm, which is faster than the fastest in stl and by exploiting some nice properties of the underlying data I basically can sort in O(n)
.
So far so good, now the problem is that I would like to offer a generic interface which will fit any type of container e.g. T*
or std::vector<T>
etc, as long as couple of key concepts apply e.g.
- there is a valid operator [] available to access the elements of the collection
- the elements of the collection support the "less than" comparable concept.
To get ideas I went to the header file <std_algo.h>
and found the function interface below which matches exactly what I'm looking for except one detail, I don't see how looping through the underlying _RandomAccessIterator
will be auto-vectorized by the compiler disregard of the container type and this is my question ... is there a way I can have it all? auto-vectorization + generic interface disregard of the underlying collection type?
I think the code below won't auto-vectorize due to the "non-canonical" loop pattern while (__last - __first > int(_S_threshold))
and conditions like if (__depth_limit == 0)
but this last I won't need in my algorithm. So I see the auto-vectorization would be prevented by the non-canonical type of loop.
template<typename _RandomAccessIterator, typename _Compare>
inline void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_function_requires(_BinaryPredicateConcept<_Compare, _ValueType,
_ValueType>)
__glibcxx_requires_valid_range(__first, __last);
if (__first != __last)
{
std::__introsort_loop(__first, __last,
std::__lg(__last - __first) * 2, __comp);
std::__final_insertion_sort(__first, __last, __comp);
}
}
The loop in question looks like this:
// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Size, typename _Compare>
void __introsort_loop(_RandomAccessIterator __first, _RandomAccessIterator __last, _Size __depth_limit, _Compare __comp)
{
while (__last - __first > int(_S_threshold))
{
if (__depth_limit == 0)
{
_GLIBCXX_STD_A::partial_sort(__first, __last, __last, __comp);
return;
}
--__depth_limit;
_RandomAccessIterator __cut =
std::__unguarded_partition_pivot(__first, __last, __comp);
std::__introsort_loop(__cut, __last, __depth_limit, __comp);
__last = __cut;
}
}
回答1:
The Standard C++ Library uses iterators in standard algorithms, such as sort(). This allows the algorithm implementation to ignore the exact details of the underlying container. Also, this approach doesn't allow for indexing with operator[]()
.
With that in mind, I have two suggestions for you to consider:
1) Revise your specialized sort to use iterators, rather than operator[]()
to access elements in the container. If it is possible to maintain your desired O(n) speed, then this is probably the most desirable method for flexibility.
2) Implement your sort with the container class templatized. Something like
template <class Container, class Compare>
void sort(Container cont, Compare comp);
should do the trick.
回答2:
The wonderful thing about templates is that they're not fully compiled until the template type is filled in, so the compiler can apply optimizations based on the final code. A T*
pointer fulfills all the required properties of a random access iterator and can be easily used in any template code that requires them.
vector<float> v;
// load v
sort(&v[0], &v[v.size()]); // same as sort(v.begin(), v.end()) but possibly optimized better
来源:https://stackoverflow.com/questions/11614758/special-sorting-algorithm-and-generic-signature