这是插入排序的两行通用 C++11 实现
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));
}
}
该算法采用一系列元素(由两个迭代器first
和给出last
)和一个比较函数(默认为operator<
指向元素的可能内置函数)。
主循环(元素数量呈线性关系)保持子区间的[first, it)
排序,并反复搜索放置下一个元素的插入点。它相当于你的主循环。它通过二进制搜索(对数复杂度)来实现。在您的代码中,您使用反向线性搜索(具有线性复杂性但可能有更好的缓存行为)。
找到插入点后,它只是旋转两个范围[insertion, it)
和[it, it+1)
,这意味着将当前元素交换到插入点。这种旋转与迄今为止已排序的元素数量呈线性关系。由于嵌套在主循环中,所以插入排序的整体复杂度是二次的,即 O(N^2)
. 您的代码集成了插入点的交换和搜索,但这不会改变复杂性。
请注意,当输入范围已经排序时,插入点将始终等于 指向的元素it
,这意味着std::rotate
根本不需要交换任何东西。足够智能和优化的编译器应该能够执行该优化。如果是这种情况,则排序范围上的插入排序具有线性复杂性。
这里给出了一个类似的 2 行选择排序方法。