Running Time For Insertion Sort

被刻印的时光 ゝ 提交于 2019-12-02 08:08:00
TemplateRex

Here's a two-line generic C++11 implementation of insertion sort

template< typename ForwardIterator, typename Compare = std::less<typename std::iterator_traits<ForwardIterator>::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.

The outer loop executes n times.

Each run of the inner loop executes somewhere between 0 and p-1 times, where p varies from 0 to n. In the worse case, it will execute p-1 times. If p varies from 0 to n, then on average, p is n/2. So, the worst-case complexity for the inner loop is O(p-1) = O(n/2-1) = O(n).

Apart from the loops, the code is all O(1) (mostly importantly, the code inside the inner loop is), so it's only the loops that matter.

O(n) * O(n) = O(n^2).

QED.

This is roughly the analysis you yourself gave.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!