for (int p=1; p < a.size(); p++) {
int tmp = a[p];
for(j=p; j>0 && tmp < a[j-1]; j--) {
a[j] = a[j-1];
}
a[j] = tmp;
}
>
Here's a two-line generic C++11 implementation of insertion sort
template< typename ForwardIterator, typename Compare = std::less::value_type> >
void insertion_sort(ForwardIterator first, ForwardIterator last, Compare cmp = Compare())
{
for (auto it = first; it != last; ++it) {
auto const insertion = std::upper_bound(first, it, *it, cmp);
std::rotate(insertion, it, std::next(it));
}
}
The algorithm takes a range of elements (given by the two iterators first
and last
) and a comparison function (which is defaulted to the possibly builtin operator<
for the elements pointed to).
The main loop (linear in the number of elements) keeps the subinterval [first, it)
sorted, and repeatedly searches for an insertion point of where to put the next element. It's equivalent to your main loop. It does so with a binary search (logarithmic complexity). In your code you use a reverse linear search (wich has linear complexity but possibly better caching behavior).
After it has found the insertion point, it simply rotates the two ranges [insertion, it)
and [it, it+1)
, which means swapping the current element into the insertion point. This rotation is linear in the number of elements that has been sorted so far. Since it is nested in the main loop, the overall complexity of insertion sort is quadratic, ie.e. O(N^2)
. Your code integrates the swapping and searching for an insertion point, but that does not change the complexity.
Note that when the input range is already sorted, the insertion point will always be equal to the element pointed to by it
, and this means that the std::rotate
does not have to swap anything at all. A sufficiently smart and optimizing compiler should be able to perform that optimization. If that is the case, insertion sort on a sorted range has linear complexity.
A similar 2-line approach to selection sort is given here.